从hash到二叉树到红黑树到B树到B+树

要搞清这个几个数据结构的问题,需要搞清楚他们的原理,并且有什么问题,然后每一个新的结构能解决什么问题。为什么会出现?为什么就用他了。

hash表:

首先hash表查序你很快,通过hash函数可以在O(1)的时间就能找到key值,且都是在内存中操作。hash表的内部实现可以已有两种方式解决hash冲突问题。一个是顺序找新地方放,一个是通过链表的方式记录冲突的key值。顺序防止有占用bucket空间的问题和bucket key清楚后的特殊标记问题。同时还带有空间扩容问题。所以一般采用链表的方式解决冲突,但是链表的方式也存在问题,虽然插入删除很快,但是查询时候需要遍历链表,性能上是问题。

二叉搜索树:

所以再次基础上通过二叉搜索树(中序遍历有序)的方式替换链表。相当于查找的话是二分查找(时间复杂度O(logn))。但是二叉搜索树有一个问题,就是这棵树在某些极端场景下会是一颗链表,这样的话就和链表的方式一样时间复杂度就成了O(n).显然这对hash的效率影响很大,为此为了解决这个问题就需要一颗二叉搜索平衡树,也就是不会变成一个链表,二叉树的高度相差不超过1.此时就出现了红黑树。

红黑树:

红黑树是一颗二叉树,且是平衡的,搜索树。因此满足快速查询,插入,删除的特点。先不要去关红黑树怎么实现的,为什么一会是红一会是黑,这个是算法就这样规定了。记住就行,或者有时间可以在细研究原理。红黑树在删除和插入时候需要调整树的平衡状态,因此会存在红黑树的旋转,这样的目的是调整树为平衡状态。这样红黑树作为hash解决hash冲突的链表后,都能大大提升hash表的性能。但是总体来讲hash表,因为bucket需要提前预分配,数据都在内存中,即便使用红黑树,红黑树的节点都在内存中。这样就闲置了hash后者红黑树不可能处理大量的数据,因此内存毕竟有限。那么在处理大量数据比如mysql, 存储引擎处理的数据量(TB/PB)级别时候使用hash 红黑树就出现了很大的问题。那怎么解决呢?还有一个问题就是红黑树,hash表只能查询单个key比较搞笑,但是如果要查询一个范围的数据在只能一个一个的遍历,性能也不高。在一个是红黑树因为是二叉树,大数据量层次会很高,如果不是全部放内存的话,则需要去盘上读,这样读盘额次数就会变多。所以。。就出现了下面的数据结构。

B树:

B树是一个多叉树,意思就是一个节点可以有多个子节点(B树中叫多少介多少介)。这样有个好处就是这个树不会太高,因此放盘的IO就会变少。整棵树按照索引(就是表的key来组织,比如表示userid<->name,则按照userid作为这个树的索引构建这棵树),此时当有索引插入B树时候,B树会根据当前节点保存的关键字的个数(就是能保存多少个userid<->name对)来添加进一个树的节点页面中。如果关键字的个数已经达到设置的最大值比如 4个,则新增加进来的的userid会导致这个节点分裂。分裂的意思就是按照(4+1)/2=2的方式,将前面2个分离成3号位的前面(左)子树,后面两个分裂成3号位userid的右子树(后面子树)。然后3好上升添加到父节点里面去。这也就是说当往B树中插入删除时候会导致树分裂合并等操作。这样当去遍历某个key的时候,则从root开始就知道往那边走,区间在哪里。然后一层一层的往下找,最终找到对应的节点,读取里面保存的userid的name值。但是B数据也存在一个问题就是范围查找的问题,也需要不停的遍历某个范围的所有的节点才能找到,而是都需要从root开始。所以在范围查找上性能也不好,为此提出了B+树。

B+树

和B树一样,B+树也存在树的分裂和合并的操作,原理和B树大概差不多。但是B+树和B树有亮点很不错一样的就是:B+树非叶子节点不存储数据,存储的是索引也就是一堆userid,所以一个非叶子节点可以存储很多usrid.这样这棵树可以做到很矮,很胖,这样对磁盘的访问次数再次降低。第二点是B+树的叶子积极点之间都是通过双向链表链接的。为什么要这样,因为这样就是就便于范围查找,比如需要查序userid<100的同学的名字,则只需要从root开始遍历找到100 userid的叶子节点,然后从叶子节点读取到数据,小于100的数据都在从这个节点开始向左直接就可以读取到,不用在从root遍历来,这样就提高了性能。所以B+树就诞生了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章