首页 > 其他分享 >[数据结构+二叉树+B-Tree和红黑树与B+Tree与hashMap原理+ concurrentHashMap的原理]析解

[数据结构+二叉树+B-Tree和红黑树与B+Tree与hashMap原理+ concurrentHashMap的原理]析解

时间:2024-05-31 10:32:54浏览次数:27  
标签:红黑树 Tree 链表 二叉树 磁盘 原理 节点

目录

数据结构:

你了解过哪些数据结构:

这些数据结构的优缺点:

二叉树:

特点:

二叉树适合做磁盘存储吗:

 缺点:

B-Tree:

b-树的查找过程:

思考:

特点:

B+Tree: 

B+树搜索过程与B树的查询过程没有区别。但实际上有三点不一样:(B+Tree优

势)

简述B+Tree:

不经历IO的情况下,可以直接使用二叉树吗?

红黑树:

红黑树具有以下五个特性:

6)红黑树任意节点其左右子树最多相差2层红节点(自动相对平衡)

缺点:

​编辑

红黑树任意节点其左右子树最多相差2层红节点。所以大致上是平衡的。

hashmap的原理:

特点:

    hashmap的put流程:

扩容时机:

    为什么不上来就树化:

    什么时候会退化成链表:

    为什么hashmap每次扩容都是2的n次幂:

    为什么选择0.75作为扩容因子:

    hashmap1.8和1.7的区别:

   concurrentHashMap的原理:

使用:

    1.7版本:

    1.8版本:


数据结构:

程序 = 数据结构 + 算法 (一段逻辑性代码);

典型实例示例容器:

(1)ArrList, LinkedList,hashMap;

(2)这些容器的底层是: ArrList(数组),LinkedList(链表),hashMap(哈希表);

你了解过哪些数据结构:

数组,链表,队列,栈,树;

这些数据结构的优缺点:

数组:

        就是一块大内存空间中有一块块小的内存空间就和船底的隔板一样,我们将来就可以把数据存进去,他的优点查询快在于数据在每一块小空间,可以通过下标快速定位到要查询的位置,缺点在与增删慢,原因在于如果原数组的内存不够用,就会创建更大新的数组并把原数组的数据拷贝进新数组完成后还需要销毁原数组所以慢.

链表:

        每一个链表都保存了前后节点的地址,增加或者删除都不会影响他的速度,不管增加或者删除他都会去找前面或者后面的节点相连,但是查询比较慢因为都需要遍历所有数据链,查两端除外.

队列:顺序消费先进先出,后进后出.

比如火车:

栈:

        jvm,方法栈,方法执行都是方法栈中执行的,最先进入的后出,最后进入的先出.

杯子里放石头:

树: 实例,mysql使用的为B+Tree

二叉树

特点:

        (把每个蓝色圆球看作一个节点)由图可以看出三点:

        1.一个主节点最多有两个子节点         2.每一个节点都只能存一个关键字         3.每一个主节点下的,两个子节点都会和主节点进行对比来分配位置,左节点关键字永远小于,右节点关键字;

二叉树适合做磁盘存储吗:

        假设:把本地磁盘(好处:在于可以保证持久性)现在把磁盘中的所有数据,都放到二叉树中作为存储,现在应用程序作为内存需要获取二叉树中数据的话,应该分层;一层一层的拿取二叉树中的数据,在结合二叉树的特点来说,一个主节点最多分两个子节点;那在面对百万级大数据量的情况下,树的层数会越来越高,我们把数据从二叉树中读取到应用内存中;使用的方法是以IO流的方式进行读取的,IO很浪费性能,随着树越来越高IO次数也会越大,性能也会越低,所以不适合做磁盘存储.

 缺点:


①由于二叉树只有最多两个子节点,因此不适合存储大量的数据
②二叉树无法动态维护树的平衡,操作不当会造成树的倾斜

B-Tree:

(二叉树进化版)是一种多路搜索树,可以让原来的二叉树变得“矮胖”---> 高度降低  浅蓝色的块我们称之为一个磁盘块,可以看到每个磁盘块包含几个数据项(深蓝色所 示)和指针(黄色所示),指针指向的是存放索引数据的磁盘页,红点表示是指向卫 星数据的指针,卫星数据就是数据库中一条实际数据记录。 如磁盘块1包含数据项17和35,包含指针P1、P2、P3,P1表示小于17的磁盘块,P2 表示在17和35之间的磁盘块,P3表示大于35的磁盘块。

b-树的查找过程:

如图所示,如果要查找数据项29,那么首先会把磁盘块1由磁盘加载到内存,此时发 生一次IO,在内存中用二分查找确定29在17和35之间,锁定磁盘块1的P2指针,内 存时间因为非常短(相比磁盘的IO)可以忽略不计 通过磁盘块1的P2指针的磁盘地址把磁盘块3由磁盘加载到内存,发生第二次IO,29 在26和30之间,锁定磁盘块3的P2指针 通过指针加载磁盘块8到内存,发生第三次IO,同时内存中做二分查找找到29,结束 查询,总计三次IO。 真实的情况是,3层的Btree可以表示上百万的数据,如果上百万的数据查找只需要三 次IO,性能提高将是巨大的。

思考:

        层数的降低,导致了IO次数的减少,保证了性能,适合做磁盘存储;但是从用户时间稳定度这个问题来讲的话,由上图来说明一个新问题的话;我们就是希望从根节点查询某个关键字哪个关键字是第一条也好,还是查哪个关键字向下查询一百万条是哪个关键字也好;查询到关键字时,查询的这两条关键字,返回给我们的时间是一样的都是0.5秒,不管查询远近时间都是相同的,但是B-Tree他做不到,B-Tree他的特点在于定位的位置是否在于我们进的节点上,如果很远就很耗费时间了,保证不了这个时间的稳定性距离越远,时间耗费的时间越长.

特点:


①他是由二叉树的基础之上演变而来,B树也叫多路搜索树
②B树的每个节点保存多个数据,这样的话我们可以在使用很少的io流次数的情况下就能够读取到数据
③B树适合磁盘存储


缺点:


①不适合范围查找
②B树查找元素存在最好和最坏的情况,因此树的时间复杂度很不稳定

B+Tree: 

(B-Tree升级版)是B-树的变体,也是一种多路搜索树,比B-tree效率更高: 1、根节点和分支节点中不保存索引数据,只用于索引,所有数据都保存在叶子节点 中。 2、所有分支节点和根节点都同时存在于子节点中且在子节点元素中是最大或者最小 的元素。 3、叶子节点会包含所有的索引数据(关键字),以及指向数据记录的指针,并且叶 子节点本身是根据关键字的大小从小到大顺序链接。 更直观的图: 1、红点表示是指向卫星数据的指针,指针指向的是存放实际数据的磁盘页,卫星数 据就是数据库中一条数据记录。 2、叶子节点中还有一个指向下一个叶子节点的next指针,所以叶子节点形成了一个 有序的链表,方便遍历B+树。

B+树搜索过程与B树的查询过程没有区别。但实际上有三点不一样:(B+Tree优

势)

1、首先B+树的中间节点不存储卫星数据,所以同样大小的磁盘页可以容纳更多的节 点元素,如此一来,相同数量的数据下,B+树就相对来说要更加矮胖些,磁盘IO的 次数更少。 2、由于只有叶子节点才保存卫星数据,B+树每次查询都要到叶子节点;而B-树每次 查询则不一样,最好的情况是根节点,最坏的情况是叶子节点,没有B+树稳定。 3、B+树叶子节点形成有序链表, 范围 查找性能更优 如:范围查找3-11的数据: B-树是逐个查询该范围内的数据; B+树范围查找3-11的过程如下图: 先从上到下找到下限元素3,然后通过链表指针,依次遍历得到元素5/6/8/9/11; 如此一来,就不用像B树那样一个个元素进行查找。 Mysql的MyIsam存储引擎和Innodb存储引擎的索引的数据结构都是 B+树结构, ES的倒排索引底层结构也是B+tree等等。

简述B+Tree:

①根节点与分支节点不保存数据,只保存数据的索引,数据只存在叶子节点上,相对稳定
②叶子节点之间会形成一个有序的双向链表,我们只需要找到链表两端数据,就可以获取到范围数据,适合范围查询

不经历IO的情况下,可以直接使用二叉树吗?

如果二叉树的所有非叶子结点的左右子树的结点数目均保持差不多(平衡),那么二叉树的 搜索性能逼近二分查找,效率还算可以;但是二叉树在经过多次插入与删除后,有可能导致 不同的结构: 右边也是一个二叉树,但它的搜索性能已经是线性的了,查询效率跟链表差不多,凸显不出 二分查找的优势,所以使用二叉树还要考虑尽可能让二叉树保持左图的结构,和避免右图的 结构,也就是所谓的二叉 “平衡” 问题;

红黑树:

红黑树又称R-B Tree,全称是Red-Black Tree, 红黑树是一种含有红黑结点并 能 自平衡的二叉查找树 。

红黑树具有以下五个特性

1)节点要么是红色要么是黑色 2)根节点是黑色 3)如果一个结点是红色的,则它的所有子结点必须是黑色的 4)从一个结点到该结点的子孙结点的所有路径上包含相同数目的黑结点。 5)每个叶子的节点都是黑色的空节点(NULL)

6)红黑树任意节点其左右子树最多相差2层红节点(自动相对平衡)

缺点:

数据量大,树高度会很高导致查找速度变慢 

红黑树任意节点其左右子树最多相差2层红节点。所以大致上是平衡的。

当我们在对红黑树进行插入和删除等操作时,对树做了修改 可能会违背红黑树 的性质。 为了保持红黑树的性质,红黑树对相关节点做一系列的调整,通过对树进行 变色 旋转 (例如 左旋 和 右旋 操作),即修改树中某些结点的颜色及指针结构,以达 到对红黑树进行插入、删除结点等操作时,红黑树依然能保持它特有的性质(五 点性质)。

无论是左旋还是右旋,都不会超过三次树旋转 。   对于JDK中集合类:TreeMap、TreeSet以及 jdk1.8之后 的 HashMap底层结构都使用了 红 黑树。 注: B-Tree、B+Tree是为了减少磁盘IO提高搜索效率; 红黑树多用于内存存储,不经历IO,只要保证二叉树的平衡就保证了搜索效 率。

hashmap的原理:

特点:

   底层使用hash表数据结构,即数组+(链表或者红黑树)


        添加数据时,计算key的值确定元素在数组中的下标,key相同则替换不同则存入链表或红黑树中
        获取数据通过key的hash计算数组下标获取元素


    hashmap的put流程:


        判断table是否为空,如果空的话,会先调用resize扩容;
        根据当前key的 hash 值,通过 (n - 1) & hash计算应当存放在数组中的下标 index ;
        查看链表是否存在数据,没有数据就构造一个 Node 节点存放在链表中;
        存在数据,说明发生了 hash 冲突,继续判断 key 是否相等,如果相等,用新的 value 替换原数据;
        如果不相等,判断当前节点类型是不是树型节点,如果是树型节点,创建树型节点插入红黑树中;
        如果不是树型节点,则采用尾插法,把新节点加入到链表尾部;判断链表长度是否大于 8, 大于的话链表转换为红黑树;
        插入完成之后判断当前节点数是否大于扩容因子阈值,如果大于开始扩容为原数组的二倍。

扩容时机:


        当数据的容量到达总容量的0.75的时候就会扩容;


    为什么不上来就树化:


        红黑树使用TreeNode比链表使用的node内存占用要大;
        为了防止dos攻击解决超长链表出现的特殊手段,几率比较小.


    什么时候会退化成链表:


        当树的元素小于6个的时候会退化成链表.


    为什么hashmap每次扩容都是2的n次幂:


        只有2的n次幂计算索引的时候才能把取模运算转换为位运算.


    为什么选择0.75作为扩容因子:


         0.75只不过说是在时间上和空间上做了一个比较好的权衡;
         大于0.75说明扩容机会少,这样会形成超长链表;
         小于0.75说明扩容机会多,链表减少,但是空间变大.


    hashmap1.8和1.7的区别:


        JDK1.7用的是头插法,而JDK1.8及之后使用的都是尾插法,JDK1.7是用单链表进行的纵向延伸, 当采用头插法时多线程环境会容易出现扩容死链(ABA)问题。


        但是在JDK1.8之后是因为加入了红黑树使用尾插法,能够避免出现逆序且链表死循环的问题。



   concurrentHashMap的原理:

使用:


    1.7版本:


        使用segment分段锁实现concurrentHashMap,每个segment的下面都有一个hashtable,这样比单个hashtable并发量要高,使用segment
        锁的方式最大支持16个并发,但是需要经过两次hash  hash时间太长

 


    1.8版本:


        去除segment分段锁的概念,改用cas+sync的方式实现concurrentHashMap,当多个线程锁定一个数组的下标的时候,让多个线程进行cas
        自旋抢锁,当抢到锁之后 直接进行写的操作,写的操作不能并发  需要结合sync完成数据的写入 


    

        

标签:红黑树,Tree,链表,二叉树,磁盘,原理,节点
From: https://blog.csdn.net/LJWfbj666/article/details/139169747

相关文章

  • Leetcode 力扣106. 从中序与后序遍历序列构造二叉树 (抖音号:708231408)
    给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。示例1:输入:inorder=[9,3,15,20,7],postorder=[9,15,7,20,3]输出:[3,9,20,null,null,15,7]示例2:输入:inorder=[......
  • Leetcode 力扣105. 从前序与中序遍历序列构造二叉树 (抖音号:708231408)
    给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。示例1:输入:preorder=[3,9,20,15,7],inorder=[9,3,15,20,7]输出:[3,9,20,null,null,15,7]示例2:输入:preorder......
  • 3598. 二叉树遍历 已知前序 中序 求后序遍历
    #include<iostream>usingnamespacestd;voidpostOrder(stringpre,stringin)//定义后序遍历函数,参数为前序遍历和中序遍历结果字符串{if(in.size()){charroot=pre[0];//获取前序遍历结果的第一个字符作为根节点intk=in.find(......
  • 深入探索Qt框架系列之信号槽原理(三)
    前面两篇分别介绍了QObject::connect和QMetaObject::Connection,那么信号槽机制的基础已经介绍完了,本文将介绍信号槽机制是如何从信号到槽的,以及多线程下是如何工作的。信号槽机制源码解析1.信号的触发以该系列的第一篇文章中的示例举例:test_moc.h:classtest_moc:p......
  • 【源码】Spring Data JPA原理解析之Repository自定义方法命名规则执行原理(二)
     SpringDataJPA系列1、SpringBoot集成JPA及基本使用2、SpringDataJPACriteria查询、部分字段查询3、SpringDataJPA数据批量插入、批量更新真的用对了吗4、SpringDataJPA的一对一、LazyInitializationException异常、一对多、多对多操作5、SpringDataJPA自定义......
  • 原理冲刺笔记
    本文成文于2024/4/8(技能高考前夜),谨以此文章纪念我三年的中职生涯基础动画设计属于数据处理MP3不支持多声道音频显示器UHD超高清4K(3840x2160),也可以指代8K(7680x4320)OSWin10组成内容:内核、用户界面、内存管理、文件系统FreeDSB:类Unix操作系统Solaris:专有的Unix操作......
  • CF 947 (Div. 1 + Div. 2) D. Paint the Tree
    时间:24_05_30原题:CodeforcesRound947(Div.1+Div.2)标签:二分/数据结构/[[DFS]]/[[模拟]]/[[树形结构]]题目大意有\(n\)个顶点的树,初始时每个节点都是白色树上有两个棋子,为\(P_A\)和\(P_B\),分别位于\(a\),\(b\)顶点\(P_A\)所在的顶点会被涂成红色,\(P_B\)......
  • 转置原理
    一、转置原理若对于一个\(n\timesm\)的矩阵\(M\),存在一个线性算法能够对于给定的\(m\)维列向量\(a\),求出\(b=Ma\),则一定存在一个线性算法能够在同时间复杂度内,对于一个给定的\(n\)维列向量\(b\)求出\(a=M^Tb\)。若第一个算法的过程为\(b=A_kA_{k-1}\cdots......
  • [后续更新中] DeerOJ的工作原理
    服务端收到请求后,会运行web文件夹下的index.php文件(由同目录下的.htaccess决定)index.php文件的内容截图如下:index.php会加载所需的函数库和类库,具体如下:require$_SERVER['DOCUMENT_ROOT'].'/app/libs/uoj-lib.php';该句是调用/app/libs/下的php文件,用来调用一些......
  • 完全二叉树查找
    描述有一棵树,输出某一深度的所有节点,有则输出这些节点,无则输出EMPTY。该树是完全二叉树。输入描述输入有多组数据,遇到0时终止输入。每组输入一个n(1<=n<=1000),然后将树中的这n个节点依次输入,再输入一个d代表深度。输出描述输出该树中第d层得所有节点,节点间用空格隔开,最后......