参考
维基百科
数据结构中各种树
数据结构之树
关于二叉树的前序、中序、后序三种遍历
二叉搜索树的平衡–AVL树和树的旋转(图解)
二叉搜索树的删除
红黑树的特性
红黑树之删除节点
本文参考了各位前辈的总结,并且加以自己的理解和整理,如有侵权,请联系我!
树定义
用来模拟具有树状结构性质的数据集合,由n(n>0)个有限节点组成一个具有层次关系的集合。
1.每个节点有零个或多个子节点
2.没有父节点的节点称为根节点
3.每一个非根节点有且只有一个父节点
4.除了根节点外,每个子节点可以分为多个不相交的子树
二叉树
每个节点最多含有两个子树的树称为二叉树
二叉树衍生出了满二叉树和完全二叉树
满二叉树
除最后一层无任何子节点外,每一层的所有节点都有两个子节点。高度为h,由2^h-1个节点构成的二叉树
完全二叉树
若二叉树深度为h,除第h层外,其它各层的节点树都达到最大个数,第h层所有的节点都连续集中在最左边。
注:完全二叉树是效率很高的数据结构,堆是一种完全二叉树或者近似完全二叉树,所以效率极高,像十分常用的排序算法,dijkstra算法,Prim算法等都要用堆才能优化,二叉排序树的效率也要借助平衡性来提高,而平衡性基于完全二叉树。
二叉树性质
1)非空二叉树,第i层节点总数不超过2i-1
2)深度为h的二叉树最多有2h-1个节点,最少有h个节点
3)具有n个结点的完全二叉树深度为log2(n+1)
4)有N个结点的完全二叉树各结点如果用顺序方式存储,则结点之间有如下关系:
若I为结点编号则 如果I>1,则其父结点的编号为I/2;
如果2I<=N,则其左儿子(即左子树的根结点)的编号为2I;若2I>N,则无左儿子;
如果2I+1<=N,则其右儿子的结点编号为2I+1;若2I+1>N,则无右儿子。
5)给定N个节点,能构成h(N)种不同的二叉树,其中h(N)为卡特兰数的第N项,h(n)=C(2*n, n)/(n+1)。
6)设有i个枝点,I为所有枝点的道路长度总和,J为叶的道路长度总和J=I+2i。
二叉树遍历
前序遍历(前根遍历):根——>左——>右
中序遍历(中根遍历):左——>根——>右
后序遍历(后根遍历):左——>右——>根
比如上图二叉树遍历结果
前序遍历:ABCDEFGHK
中序遍历:BDCAEHGKF
后序遍历:DCBHKGFEA
深度优先遍历(DFS)
从根节点出发,沿着左子树方向进行纵向遍历,直到找到叶子结点为止。然后回溯到前一个结点,进行右子树结点的遍历,直到遍历完所有可达节点为止。
利用数据结构-栈,父节点入栈->右子节点入栈->左子节点入栈,以此递归遍历全部节点。
广度优先遍历(BFS)
从根节点出发,再横向遍历二叉树层段节点的基础上纵向遍历二叉树的层次。
利用数据结构-队列,父节点入队,父节点出队列,左子节点入队,右子节点入队,递归遍历全部结点
二叉查找树(Binary Sort Tree)
又称为二叉排序树(Binary Sort Tree),或二叉搜索树(Binary Search Tree)
时间复杂度:插入和查找的时间复杂度均为O(logn),但在最坏的情况下仍然会有O(n)的时间复杂度。
对二叉查找树进行中序遍历,即可得到有序的数列。
二叉查找树的高度决定了二叉查找树的查找效率。
1)若左子树不为空,则左子树上所有结点的值均小于根节点的值
2)若右子树不为空,则右子树上所有结点的值均大于或等于根节点的值
3)左右子树也分别为二叉排序树
4)没有键值相等的节点
查找
若二叉搜索树为空,则查找失败,返回空指针
若二叉搜索树非空,则将给定值key与根节点的进行比较
->若key等于根节点,则查找成功,返回根节点地址
->若key小于根节点,则递归查找左子树
->若key大于根节点,则递归查找右子树
插入
1)若当前的二叉查找树为空,则插入的元素为根节点
2)若插入的元素小于根节点,则将元素插入到左子树中
3)若插入的元素值不小于根节点值,则将元素插入到右子树中
删除
二叉查找树的删除,分为三种情况处理
1)z为叶子节点,则直接删除该节点,再修改父节点的指针
2)z为单支节点(只有左子树或右子树)。让p的子树与p的福清节点相连,删除p即可
3)z的左子树和右子树均不为空。
方法一:找到z的后继y,因为y一定没有左子树,所以可以删除y,并让y的父亲节点成为y右子树的父亲节点,并用y的值代替z的值,如图c
方法二:找到z的前驱x,x一定是没有右子树,所以可以删除x,并让x的父节点成为x左子树的父亲节点
总结:找到要删除节点右子节点中的最小值或者左节点中的最大值,代替要删除的节点即可
后继和前驱
把二叉查找树中序遍历后得到有序的一串数字:1,5,7,20,49,102,490
比如节点7的前驱就是5,后继就是20
平衡二叉树(Balance Binary Tree)
起源
一般二叉搜索树,其期望高度为O(log2n),各操作的时间复杂度O(log2n)同时也是由此决定的。
在某些极端情况下(如插入的序列是有序的)二叉搜索树将退化成近似链或链,此时操作的时间复杂度将退化成
定义
平衡二叉树又被称为AVL树
它是一棵空树或它的左右两个子树高度差绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
平衡二叉树常用算法有红黑树,AVL树等。
再平衡二叉搜索树中,其高度一般都良好的维持遭O(log2n),大大降低了操作的时间复杂度
最小平衡二叉树的节点公式如下
F(n) = F(n-1) + F(n-2) + 1
1是根节点,F(n-1)是左子树的节点数量,F(n-2)是右子树的节点数量
AVL树
定义
AVL树是最先发明的自平衡二叉查找树。
n个节点的AVL树最大深度约 1.44log2n
查找,插入和删除在平均和最坏情况下都是O(log2n)
增加和删除可能需要通过一次或多次树旋转来平衡这棵树。
但是频繁的旋转会使插入和删除牺牲掉O(log2n)左右的时间
旋转
AVL树自平衡操作-旋转,AVL树最关键也是最难的一步操作。
为了实现AVL树在实施插入和删除操作以后,树重新回到平衡的方法。
四种不平衡状态如下:
1)6节点的左子树3节点高度比右子树7节点大2,左子树3节点的左子树1节点高度大于右子树4节点,这种情况成为左左。
解决方法:左旋(单旋转)
2) 6节点的左子树2节点高度比右子树7节点大2,左子树2节点的左子树1节点高度小于右子树4节点,这种情况成为左右。
解决方法:左子节点右旋,根节点再左旋(双旋转)
3)2节点的左子树1节点高度比右子树5节点小2,右子树5节点的左子树3节点高度大于右子树6节点,这种情况成为右左。
解决方法:右子节点左旋,根节点再右旋(双旋转)
4)2节点的左子树1节点高度比右子树4节点小2,右子树4节点的左子树3节点高度小于右子树6节点,这种情况成为右右。
解决方法:右旋(单旋转)
左旋
左旋——自己变为右孩子的左孩子
右旋
右旋——自己变为左孩子的右孩子
AVL树的缺点
插入时要维护其绝对平衡,旋转的次数比较多
删除时可能要让旋转持续到根的位置。
因此,如果需要一种查询高效且有序的数据结构,并且数据个数为静态的,可以考虑AVL树,但结构经常被修改,就不太适合,所以引出了红黑树
红黑树
介绍
红黑树是一种自平衡二叉查找树,典型用途是实现关联数组。
有着良好的最坏情况运行时间,查找,插入和删除的时间复杂度都是O(logn),n为树中元素的数目。
红黑树和AVL树一样都对插入时间,删除时间和查找时间提供了最坏情况担保。不只使它们在时间敏感的应用中有价值,而且使它们有在提供最坏情况担保的器它数据结构中作为建造板块的价值,例如在计算几何中使用的很多数据结构都可以基于红黑树。
性质
1)节点是红色或者黑色
2)根节点是黑色
3)所有叶子节点都是黑色
4)所有红色节点的子节点必须为黑色(从每个叶子到根的所有路径上不能有两个连续的红色节点)
5)从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点
这些约束确保了红黑树的关键特征:从根到叶子的最长路径不多于最短路径的两倍长。
理论上允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树。
操作
查询操作:因为红黑树也是一个特化了的二叉查找树,因此红黑树上的只读操作与普通查找树只读操作相同
插入和删除操作:会导致不再符合红黑树性质,恢复红黑树的性质需要O(logn)的颜色更变和不超过三次树旋转(插入操作为两次树旋转)。虽然插入和删除很复杂,但操作时间仍可以保持为O(logn)
插入
红黑树插入新节点时新节点默认设置为红色(将红黑树的节点默认颜色设置为红色,是为尽可能减少在插入新节点对红黑树造成的影响,如果设为黑色,就会违背红黑树性质4,并且很难调整,但是设置为红色节点后,可能会导致两个连续红色节点的冲突,可以通过颜色调换和树旋转来调整)。
• 性质4只会在增加红色节点,重绘黑色节点为红色,或做旋转时受到威胁
• 性质5只会在增加黑色节点,重绘红色节点为黑色,或做旋转时受到威胁
插入分为五种情形(插入操作跟二叉查找树的插入流程相同)
情形1:红黑树为空,新节点N位于树的根上,没有父节点。
解决方案:违背红黑树性质2,将节点N从红色重绘为黑色
情形2:新节点的父节点P是黑色。
解决方案:此时情况下即不违背性质4,也不违背性质5,所以可以不做处理
情形3:如果父节点P和叔节点U两者都是红色(此时新插入节点N作为P的左子节点或右子节点都属于当前情形,当前例子为N作为P左子节点情形)
G为根节点的情况:
解决方案:此时将P节点和U节点重绘为黑色,并重绘G节点为红色,用来保证性质5;但节点G可能是根节点,这样就违反了性质2(解决:将父,叔节点,祖父节点都设为黑色);也有可能G节点的父节点是红色,这样就违反了性质4。为了解决问题,可以在节点G上递归地进行情形1地过程(把G当成是新加入地节点进行各种情形检查)
接下来的情况中,我们假设父节点P是祖父节点G的左子节点。如果它是右子节点,情形4和情形5中的左右应当对调
情形4:父节点P是红色而叔父节点U是黑色或缺少,并且新节点N是其父节点P的右子节点而父节点P又是其父节点的左子节点
解决方案:先进行一次左旋转调整N节点和P节点的角色,此时会违反性质4,我们交给情形5去处理。
情形5:父节点P是红色而叔父节点U为黑色或缺少,新节点N是其父节点P的左子节点,而父节点P又是其祖父节点G的左子节点。
解决方案:对G节点进行一次右旋转,并重绘P节点和G节点的颜色(为了满足性质4,性质5也保持满足)
删除
红黑树删除的所有情况
D为删除的节点,S兄弟节点,SL兄弟节点的左子节点,SR兄弟节点的右子节点,P父节点
3.2.2.1 D=黑,S=红,D为左节点(P和S颜色对调,P左旋,进入情况3.2.4)
处理后:
3.2.2.2 D=黑,S=红,D为右节点(P和S颜色对调,P右旋,进入情况3.2.4)
处理后:
3.2.3.1 D=黑,S=黑,S不为叶子节点,SR不为空,D为左节点 (P和S颜色对调,SR涂黑,P左旋,删除D)
处理后:
3.2.3.2 D=黑,S=黑,S不为叶子节点,SR不为空,D为右节点(P和S颜色对调,SL涂黑,P右旋,删除D)
处理后:
3.2.3.3 D=黑,S=黑,S不为叶子节点,SR为空,D为左节点(S和SL颜色对调,S右旋,P与当前右子交换颜色,P左旋,S涂黑,删除D)
处理后:
3.2.3.4 D=黑,S=黑,S不为叶子节点,SL为空,D为右节点(S和SR颜色对调,S左旋,P与当前左子交换颜色,P右旋,S涂黑,删除D)
处理后:
3.2.4 D=黑,S=黑,S为叶子节点,P=红 (P和S颜色对调,删除D)
处理后:
3.2.5 D=黑,S=黑,S为叶子节点,P=黑(S涂红,删除D,并将P作为D节点做平衡操作,将P的P,P的P的P……一直到根节点都做平衡操作)
处理后: