算法数据结构-树(1)

此文包含树,二叉树,满二叉树,完全二叉树,二叉查找树(BST Binary Search Tree,也可以成为排序二叉树,有序二叉树),平衡二叉树(BBT),红黑树,B-树,B+树,B*树。这里暂时不包含各树的java实现。其实下述概念只是本人一些笔记加深自己的理解

1:树

2:二叉树

每个节点最大只存在左右两个节点

3:满二叉树

对于一个深度为h的二叉树中,若节点的个数为2^h-1,则代表该树为一个满二叉树

4:完全二叉树

完全二叉树其实是

5:二叉查找树(Binary Serach Tree)

二叉查找树简称BST,又称为有序二叉树,排序二叉树,从名称可以看出,对于树中的节点是有序存在的,即左叶节点不为空的话肯定是小于跟节点的,那么对应的右叶节点不为空的话肯定是大于跟节点的,任意节点的左、右子树也分别为二叉查找树,不存在健值相同的节点。对于一个二叉查找树的查询时间复杂度为(O(log(n)最优的情况就是一个平衡二叉树-O(n)最差情况和链表的效率差一样,实际上最差情况它就是一个有序链表))

6:平衡二叉树(Balanced Binary Tree)

平衡二叉树可以简称BBT,它是二叉查找树的一个升级版,也是第一个引入平衡的树,它可以保证的查询的时间为O(log(n)).对于平衡二叉树来说,除了包含二叉查找树的特点之外,还有自己的要求:对于任意一个节点,它的左右子树的高度相差的绝对值不能超过1,若应为插入或者删除导致了这一条件不能符合,就会进行节点的旋转,最终要使这条件满足,使的整棵树肯定是维持一个平衡的状态,这也保证了不会因为节点的增删,导致其退化为一个有序链表最终,整个查询变为了O(log(n)).但是虽然平衡二叉树查询时间上有了保证,但是也是极大的增加了增删的复杂度(因为这里涉及到节点的旋转)。

7:平衡二叉树之2-3树

 

8:红黑树

红黑树也是平衡二叉树的升级版,红黑树是一个不完全平衡的二叉树(红黑树的某些节点可的左右子树的高度是相差超过1的),但它和平衡二叉树的查询时间复杂度一样为O(log(n)),但相对于平衡二叉树它的增删要简单的很多,它可以保证增删的时间复杂度一样为O(log(n))。红黑树在普通二叉树的基础上对每个节点增加了颜色的概念,它包含了下列5种特有的性质:

  1. 节点非红必黑
  2. 根节点必为黑色
  3. 每个叶节点(null或空节点)为黑色
  4. 对于红色节点它的子节点只能为黑节点(也就是说不存在连续的黑节点)
  5. 对于任意的节点到达任意尾节点(叶节点),中间经过的黑色节点数相同。这点也就是为何它被称为一个不完全平衡二叉树

红黑树在很多地方都有涉及例如java中hashmap在1.8之后,对于hash冲突的数据使用链表存储,但一旦链表中的元素个数超过了8那么就会将链表转化为红黑树,所以对于这一块代码的实现可以参考hashmap源码。

9:B树(B-Tree)

B树与上述树不同它不是一个二叉树,它是一个平衡多叉树,意味着它的任意节点可以包含多个子节点。它有着以下规则:

  1. 从子节点的角度来看:任意一个节点的子节点的数量在[2,M]之间(注:M阶代表一个树节点最多有多少个查找路径,M=M路,当M=2为2叉树,M=3为 3叉树),当然空树除外
  2. 从节点包含的关键字(关键字为参与树中排序的值,即可以为该值也可以为该值中的某个属性)的角度来看:任意一个节点中包含的关键字个数在[ceil(M/2)-1,M-1]之间(注:ceil()函数是一个向上取整的函数,即ceil(1.5)=2)
  3. 非叶子节点的关键字的个数=指向子节点的数量-1
  4. 如果假设任意一层关键字为K[1], K[2], …, K[M-1],并且满足K[i] < K[i+1];当前层中对应的子节点指针为P[1], P[2], …, P[M];那么P[1]指针指向的是小于K[1]的值,P[2]指针指向的是k[1]-k[2]之间的值依次下去,P[M]指针指向的是大于K[M-1]的值。若当前P[]指针无值指向就带空。
  5. 从排序方式来看:所有节点的关键字是按照增续的方式进行排序,依照左小右大的方式
  6. 所有的叶子节点都在同一层

如下图所示是一个M=3的B树:

对于B树与平衡二叉树来说最大的区别在于节点中包含的子节点的数量,也就是平衡二叉树相对于B树在树深上极大的减少(减少的多少与M值有关系),这也代表了B树的数据查询的次数已经复杂度降低。B树最优查询时间复杂度为O(log2(n)),n为关键字的个数(等同于二分法查找),与M无关。

特点:

B树相对于平衡二叉树的不同是,每个节点包含的关键字增多了,特别是在B树应用到数据库中的时候,数据库充分利用了磁盘块的原理(磁盘数据存储是采用块的形式(这是计算机管理存储器的逻辑块,硬件及操作系统往往将主存和磁盘存储区分割为连续的大小相等的块)存储的,每个块的大小为4K,每次IO进行数据读取时,同一个磁盘块的数据可以一次性读取出来,避免多次io操作)把节点大小限制和充分使用在磁盘块的大小范围;把树的节点关键字增多那么后树的层级比原来的二叉树少了。

10:B+树

B+树是B树的升级版,相对于B树,B+树的空间使用更少,平均查询效率完全接近与二分法查找法。B+树涞源与B树,所以B+树的基本定义与B树相同,除了有几点特殊:

  1. 任意一个非叶子节点中包含的关键字的数量和子节点的数量相同(也有认为和B树一样的为m-1),非叶子节点中不保存实际的数据(这点与B树也是不同,B树包含实际数据),只作为索引存在,实际的数据都保存在叶子节点中(这也是为何下图中叶子节点中包含了对于区段内的所有节点数),这样使得所有的查询都会落到叶子节点,因为对于b+树来说,所有叶子节点都在最后一层,也就意味着任意的查询,它对应查询的步骤都是相同的,其性能也等价于在关键字全集做一次二分查找,也就是O(log2(n))
  2. 非叶子节点中P[i]节点指向的是关键字范围在[K[i],K[i+1])(注:这里是半闭区间,B树是一个开区间),也可以这么理解每一节点关键值的最大值为父节点中最大值或者最小值。例如下图中第一层中的5其子节点中最小值。
  3. B+树为所有叶子结点增加一个链指针, 这样所有叶子节点就构成了一个有序(升序)链表

B+树与B树对比:

  1. 对于数据库中索引的应用场景来说,上文说到了每一个节点对应着一块磁盘块,因为对于B+树来说,非叶子节点不保存原始数据,这样相对于B树来说它在每一个节点中存储的关键字就会越多,那么对应的树的层度就会降低。相同的数据情况来说,整体B+树是要比B树要更矮胖这样对应的查询的效率最高。
  2. B+树整体查询性能稳定,不会向B树那样差距很大(原因在于B+树要查询到叶子节点才结束,而B树只需要匹配到合适节点结束那么最优情况下到根节点结束(这也是B树相对于B+树来说的优点),最差情况下也要匹配到叶子节点)。
  3. B+树全节点遍历更快:B+树因为叶子节点中包含了该树对应的所有数据,并且本质为一个有序链表,所以在便利起整个Tree中数据,B+树有着天然的优势。对于数据库中来说更是如此,在全表扫描的查询,B+树的优势体现无疑。
  4. B+树相邻接点的指针可以大大增加区间访问性,可使用在范围查询等,而B-树每个节点 key 和 data 在一起,则无法区间查找。

11:B*树

B*树是B+树的升级版,相对于B树在树的非根和非叶子结点再增加指向兄弟的指针;如下图所示:

对于当前非叶子节点中关键值与子节点的关系最少满足(2/3)*M的关系(B树,B+树中最少要满足(1/2)*M的关系),即当前块的使用率为从50%升到66%

对于B+树与B*的最大区别在于节点的分裂时:

  1. B+树的分裂:当一个结点满时,分配一个新的结点,并将原结点中1/2的数据复制到新结点,最后在父结点中增加新结点的指针;B+树的分裂只影响原结点和父结点,而不会影响兄弟结点,所以它不需要指向兄弟的指针;
  2. B*树的分裂:当一个结点满时,如果它的下一个兄弟结点未满,那么将一部分数据移到兄弟结点中,再在原结点插入关键字,最后修改父结点中兄弟结点的关键字(因为兄弟结点的关键字范围改变了);如果兄弟也满了,则在原结点与兄弟结点之间增加新结点,并各复制1/3的数据到新结点,最后在父结点增加新结点的指针;

从上述的描述可以看出,因为B*树分配新结点的概率比B+树要低所以B*树对于空间利用率要高于B+树。

总结:

其实不论二叉树,平衡二叉树,红黑树,B树,B+树,B*树从总体来看,它的思想都是使用二分法+数据平衡来提高平均查询效率,但每一种树都有自己的优缺点,适用于不同的场景情况下,没有哪一种数据结果可以说囊括解决所有的需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值