前言
在C++数据结构的学习中,AVL树的实现可以算是刚开始接触二叉树的难点了,相比于普通的二叉搜索树,AVL树可以通过旋转调整平衡,旋转怎么实现书上应该都会讲,而且书上举的例子都可以通过旋转平衡,你是否有这样的疑问:1.旋转思维的底层逻辑是什么(即怎么想到的)?2.怎么保证所有情况都可以通过旋转调整平衡(即为什么可以这样做)?第一个涉及对二叉树深层理解(我感觉还需要一定的空间想象能力),我就直接说明第二个问题。
分类
AVL树的旋转可以抽象为四个抽象图来概括一类情况
先证明为什么有4种:
当需要旋转时,一定是某个节点的左右节点的高度差的绝对值为2,且新插入的元素是插在高的一方或其子树,又左右都可以为高的一方,这就有了两种情况
不妨设为右节点高左节点2
则右节点的子树(如果有的话)的左右子树的高度差一定是1
证明:
高度差若为0,则插入这个新元素后高度不变,即在插入这个元素之前就已经需要旋转了,矛盾。
高度差若大于1,则递归到这个子树的时候就已经需要旋转了,矛盾。
证毕
同样左右子树都可以作为高的一方,又有了两种情况,故一共2*2=4种
至于为什么不继续讨论,因为之后的情况都在抽象图内
我们简称需要旋转的节点的左子树高于右子树,且左子树的左子树高于右子树为左左。
则左左可以抽象为
其中圆为一定存在的节点(不然没办法旋转),方框为子树,方框内的数值为高度
通过上面分析可以知道相对高度是完全确定的,且这样的抽象图已经可以用来旋转。
二右右的情况是同理。
接下来就是左右和右左的情况了,这个需要双旋,情况复杂一些
以左右举例,可以抽象为
其中蓝色的箭头为下一个可插入的元素,下面证明为什么一定是这样
若需要旋转,旋转的左右子树之差一定是2,由于我们是左右情况,设右子树的高度为h,则左子树的高度一定为h+2,由上面分析可知,左子树的左右子树高度差一定是1,由于我们是左右情况,且总高度为h+2,故左子树的左子树一定高度为h,右子树高度一定是h+1,同理可得,左子树的右子树的子树高度一定是h且左右子树的高度差不超过1,故在上面情况下,从蓝色箭头的任意位置插入都符合要求,且可以概括全部可能。
证毕
右左情况同理,这里就不过多赘述了。
接下来可以用这4中抽象图带一下旋转的操作,你会发现都可以实现平衡,而这四种抽象图可以概括所有需要平衡的情况,也就得出了旋转一定可以平衡
证毕!