搜索二叉树,AVL树,红黑树

数据的逻辑结构分为线性结构和非线性结构。

线性结构:一对一关系

非线性:

树形结构:一对多关系

图形或网状结构:多对多关系

集合:结构中的数据元素之间除了“同属于一集合”的关系外,别无其他关系


当向二叉排序树中插入一个结点,则该结点一定成为叶子结点。

总是在最底层找到一个合适的位置,不用考虑是否平衡,极端情况就是一直插入比上一个大的,退化成链表,但插入的新节点,始终是二叉排序树的底层叶子结点,所以在最高层数插入,层数就会+1;因为比着比着,总有更接近,只要不相等的话,细分的越来越精确,直到到了底层,没了,就比不下去了

目说的是二叉排序树,插入在叶子结点,不需要调整。

而AVL树才需要调整,此时不一定是叶子结点

高度差,又名平衡因子,范围为[-1,0,1],在此规定平衡因子 bf = 右子树的高度-左子树的高度

当有新的结点插入之前,该树一定是一个平衡二叉树

按照普通搜索树的方式插入结点cur(即直接作为叶子结点,在底层找到对应的位置)
插入之后,调整cur的 parent.bf:插入到左边 bf --;插入到右边 bf++;(插入后,对层数造成了影响,进而使平衡因子发生改变)
bf变为3种值:
(1)0:插入结束
(2)-1/1:调整 bf 的过程向上蔓延
(3 )-2/2:进行修复,
对失衡的情况进行修复
插入完成之后,该树依然是一个平衡二叉树

具体步骤
通过查找,找到key的合适的位置并将key插入(如果已经存在,则放弃查找

设置并修改平衡因子:

设置新插入的结点 cur 的平衡因子,新插入的结点的平衡因子是 0(未调整的),因为一定插入在叶子结点
修改 cur 的父节点 parent 的平衡因子 bf
如果cur是parent的左子树,parent.bf -= 1
如果cur是parent的右子树,parent.bf += 1
修改parent.bf 之后,parent.bf 的取值范围为 [-2,-1,0,1,2]

只要紧相连的父节点平衡因子因插入而变为1时,就要对全部的父节点的平衡因子做一次调整

直接插入并不会使与之相邻的父节点的平衡因子超过1,最多使其到1,真正到2的,是在紧相连的父节点到1后对其他父节点的平衡因子的调整,才使其从原本的1进一步到2

失去平衡的调整方法:
解决失衡的方法口诀
左左失衡,parent右旋;
左右失衡,cur左旋,parent右旋;
右右失衡,parent左旋;
右左失衡,cur右旋,parent左旋;
解析:parent为当前失衡的结点cur为parent的孩子新结点所在的子树根节点,并非插入的新节点


 

如果从根节点(失衡的结点)到新插入的结点一路向左,即左左失衡(00);如果中途向右了(先向左后向右,01),即左右失衡;如果一路向右,即为右右失衡(11);如果中途向左了,即右左失衡(先向右后向左,10); 

失衡就代表层数差到了2,就是失衡结点到新增结点共有两步路,每步路共有两个方向,则实质上共有4种本质情况.且失衡的部分层数一定是2

本质即为LL,LR,RL,RR,共有三个点(失衡的根节点,中间结点,新增结点),两个方向(失衡的根节点到中间结点,中间节点到新增结点)

出现这种情况是因为10有左结点9,从而使10平衡了一下,但7并没有,实质上还是RR情况,看的时候可以去掉9,9在左旋时也要归到7的右节点上 (10失衡的时候7一定失衡,7失衡的时候10不一定失衡,因为10的规模更小,左右子树要求为AVL的限制不明显,更容易被平衡)

左旋:指将根节点的右侧往左拉,原先的右子节点变成新的父节点,并把多余的左子节点出让,给已经降级的根节点当右子节点。

左侧是比根节点小的,右侧是比根节点大的

左旋后,原本有两个儿子的根节点变成只有一个儿子,类似于原来是多个不等式,现在变连续了(b为根节点,a<b(左儿子a),b<c(右儿子c)变为c为根结点,a<b<c,(a,b都是c的左儿子)(a是b的左儿子),层数肯定是b为根节点时更低,因为空间利用得充分,而c时,只利用了左儿子空间)

多余的左子结点比原来的根结点大,又比新的根节点小,接在原来的根节点右侧。

根节点当左儿子,右儿子当根节点

treenode* zuo(treenode* root){
treenode* temp=root->right;
root->right=temp->left;
temp->left=root;
return temp;}

保留根节点原有的左节点,左旋的结点若有左节点,则把它作为降级的根节点的右节点

左旋的结点在根节点右侧,值都比根节点与其左侧大,在这左旋过程中,原本的根节点失去了右节点(左旋的结点,作为了新根节点),左旋的结点失去了左结点(保留根节点原有的左节点,失去了自己的),所以令游离的左节点填补到原本根节点的右节点空缺上

左右旋是针对根节点而言的,是根节点左右旋,而非变成新根节点的结点

右旋:指将根节点的左侧往右拉,原先的左子节点变成新的父节点,并把多余的右子节点出让,给已经降级的根节点当左子节点

左右旋后依然满足排序规则,前后状态等价,只是高度不同

所谓左旋与右旋,实际上就是对等价状态的一次转化,变化的原因就是因为父节点(主语)发生了改变,从而使描述相对关系的符号(谓语),图像发生了转变,但他们之间的相对关系是不变的。

如a<b与b>a是等价的

插入48以后,该二叉树根结点的平衡因子由-1变为-2,在最小不平衡子树根结点的右子树(R)的左子树(L)中插入新结点引起的不平衡属于RL型平衡旋转,需要做两次旋转操作(先右旋后左旋)。

 

”左左失衡,parent右旋“(插入的元素一直比上一个小,在左子树不断积累,则选中间的那个(cur),使它成为父节点,a<b<c(左左失衡,此时a<b的主语是b,a在b的左子树上,表示a比b小),转变成b>a,b<c(选中间的为根节点))

  • “左右失衡,cur左旋,parent右旋”:(初始在左子树,说明比根节点小,又向右,说明比当前父节点大)(a<b,b<c只不过b在a的右子树(表示比a大,此时主语就是a,而不是b,通过左旋,使a从主语转变为宾语,b转变为主语)

 “右右失衡,parent左旋

 

右左失衡,cur右旋,parent左旋”:

 

左子树高:右旋;右子树高:左旋; 

LR,RL的情况,都是通过先对cur进行旋转,使之成为LL,或RR的情况,再让根节点旋转,LL,RR的情况可通过旋转一次完成,

先向左(LR)就先左旋,先向右(RL)就先右旋,目的都是把子树整成LL或RR的情况,再通过对父节点旋转一次实现平衡

左旋就意味着原来的根节点成为新的根节点的左儿子(新的根节点是原来根节点的右儿子,原来的根节点比新的根节点小),新的根节点必须舍掉原来的左儿子(比新的根节点小,比原来的根节点大)而使其变成原来的根节点,同时新的根节点是原来根节点的右儿子,意味着原来根节点必须舍弃原来的右儿子,而使其变成新的根节点舍弃的左儿子(比新的根节点小(在新树的左侧),同时比原来的根节点大(在左侧的右侧))

右旋就意味着原来的根节点变为右儿子,失去一个左儿子(原来的左儿子是新的根节点,比原来的根节点小),新的根节点(原来的根节点的左儿子)舍弃掉原来的右儿子,接上原来的根节点,原来的右儿子(比新的根节点大,同时比原来的根节点小)接到原来的根节点的左侧。


 红黑树是一种含有红黑结点并能自平衡的二叉查找树

自平衡,通过插入时的红黑转换来实现

即,红黑树不用考虑高度差,只需要保证颜色符合规则就行,保证这一点(主要是每条分支的黑色数量相同),就能保证树是平衡的
1.任意结点都有颜色,红色或者黑色
红黑树中根节点一定是黑色的
红黑树中的 null 位置看作是黑色
红黑树中红色不能与红色相邻
5.从根到所有 null 的路径上黑色结点的个数相同
红黑树中,最长的路径的长度,不会超过最短的路径的长度的2倍
时间复杂度:Olog(n)
 

 插入操作过程
start:一颗红黑树
按照搜索树的特征进行插入
插入时:插入的结点一定是红色的,如果为黑色,会破坏第五条规则
如果插入的结点是根节点,将颜色改为黑色
插入的结点的父结点是黑色的,则插入完成

如果插入的父节点是黑色,则直接完成,不用管了
插入的结点的父结点是红色的,则需要修复,且继续向上调整,直到为根或满足规则

只有插入时,父节点是红色时才需要修复。即无法在同一个位置没有条件的连续插入两次
如果根修改之后为红色,一定要改过来,改为黑色
end:一颗红黑树

修复方法
  • 前提条件:插入的结点(cur)是红色,cur的父结点(parent)是红色的,这样的需要修复
  • 修复要点:保证修复操作前和修复操作后的黑色结点的数量不变
  • 可推断出:cur 的祖父结点即父亲的父亲(grandpa)一定是黑色,否则插入当前结点之前已经违反了红黑树的规则

  • 情况1:uncle 存在(uncle != null),并且 uncle 的颜色是红色

修复方法:grandpa 由黑变红,parent & uncle 由红变黑;

cur是左还是右孩子无所谓

(这种情况不用动结点,只用改颜色,就因为有红色的兄弟结点,可以保证改颜色后,黑色的数量不变,相当于AVL里的平衡状态)

如果祖父结点就是根节点,则要把它再变成黑色,即不能出现连续的红色,但可以出现连续的黑色

情况2:uncle 不存在,或者 uncle 存在但是颜色是黑色
情况2.1:cur 是 parent 左孩子,且 parent 是 grandpa 的左孩子
修复方法: grandpa 右旋之后颜色变为红色,parent 的颜色变为黑色


eg:
情况2.2:cur 是 parent 的右孩子,且 parent 是grandpa 的右孩子
修复方法:grandpa 左旋后颜色变为红色,parent 颜色变为黑色


eg:
情况2.3:cur 是 parent 的右孩子 ,parent 是 grandpa 的左孩子
修复方法:对 parent 左旋之后将 parent 和 cur 的名称交换,再按照2.1的情况处理
eg:
情况2.4: cur 是 parent 的左孩子 ,parent 是 grandpa 的右孩子
修复方法:对 parent 右旋之后将 parent 和 cur 的名称交换,再按照2.2的情况处理
eg:
演示

 

 


 

 

 

平衡二叉树:深度为h

最小结点数(即最小平衡二叉树的结点数):f(h)=f(h-1)+f(h-2)+1。其中f(0)=0,f(1)=1。1表示根节点,f(h-1)表示左子树的节点数量,f(h-2)表示右子树的结点数量

最大结点数 2^h-1

某结点的左子树与右子树的高度(深度)差即为该结点的平衡因子(BF,Balance Factor)。

平衡二叉树上所有结点的平衡因子只可能是 -1,0 或 1。

若平衡二叉树的高度为6,且所有非叶结点的平衡因子均为 1,则该平衡二叉树的结点总数为20

除叶节点外平衡因子都为1,说明左子树都比右子树高度多1,也就是说,是左子树撑起了该局部根节点的高度,所以可以按照这样的思路,自顶而下画这棵树:(节点标号是为了区分各个节点)


 

 要构成n层的平衡二叉树,需要左右子树均为平衡二叉树,要问最小的结点数,那么需要左右子树不等高,不然一定不是最小结点数,设左子树高,去掉根节点,则左子树为n-1层,那么右子树为n-2层,而且均为AVL,左子树又为n-1层最少的结点数的AVL,那么左子树的左子树与左子树的右子树又都是AVL,且层数差一,所以为递归,即f(n)=f(n-1)+f(n-2)+1;n-1指左子树,占n-1层,n-2指右子树,比左子树少一层,为了最少的结点数,1指根节点,与左子树共同构成N层


线索二叉树中左右孩子如果为空会分别指向前后驱节点,所以判定孩子为空的标准就是看此节点是否是左右线索。是左线索则左孩子原本为空

tag=1则表示用来线索化,存储的是前驱或后继,不然则表示存储的是孩子

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值