背景:
二叉平衡树,就是根据二叉搜索树进行优化,让其速度更加的快,如果读者没有学过二叉搜索树,可以前往以下链接查看资料:
http://t.csdn.cn/Sjjjshttp://t.csdn.cn/Sjjjs
二叉搜索树的缺陷:
在以上链接中,我们讲解了二叉搜索树:就是一个二叉树,有着特殊的性质,搜索时间很快!但是这有着一个致命的缺陷,我们给出一个例子,假设我们输入1,2,3,4,5,6,组成的二叉搜索树是这样的:

这样的二叉搜索树,不就和普通的数组查找时间一样吗?连二分查找都不如,会浪费二叉树的大把空间,我们再看一个例子,输入6,5,4,3,2,1的二叉搜索树是这样的:

以上这个二叉搜索树是根据输入的递减序来进行创建的,而图1.1则是通过递增序输入而造成的二叉搜索树,所以我们知道,如果我们的输入是递增、递减序的话,那么组成的二叉搜索树的搜索时间就和数组一样的。
所以我们要进行优化,怎么优化呢?就是在二叉搜索树的基础上优化出一个AVL数(二叉平衡树)来。
二叉平衡树简介:
平衡二叉树也叫做AVL树,AVL树的名字来源于它的发明作者G.M. Adelson-Velsky 和 E.M. Landis。AVL树是最先发明的自平衡二叉查找树(Self-Balancing Binary Search Tree,简称平衡二叉树。
我们怎么知道这棵二叉搜索树平不平衡呢?我们知道,二叉搜索树的搜索时间和高度是有直接关系的,但是我们按递增、递减序输入之后,高度就和n一样了,所以时间复杂度为O(log n).想要优化,就是改变这棵二叉搜索树的高度。
首先,我们就是要知道,怎么样才要改变二叉搜索树的高度,难道只是递增、递减序的输入吗?不是的,只要左子树高度与右子树高度没有高度平衡的话,我们就需要进行一次改变二叉搜索树高度的操作。
什么叫高度平衡呢?就是两者高度相减的绝对值(abs函数可以求解)c,如果c不等于0(高度一样),不等于1,不等于-1(等于1和-1都是两者相差1),那么说明次二叉搜索树不是高度平衡,反之,这棵二叉搜索树就是高度平衡。
假设呢?我们输入1,2,3来组建二叉搜索树:

每一个节点上方都有两个数字,左边的代表其左子树的高度,右边的代表其右子树的高度,从根节点开始,右子树减左子树的绝对值为2,不是-1,0,1,所以这不是一颗高度平衡的树,那么怎么样才是高度平衡的树呢?
以下为输入1,2,3后组成的一颗高度平衡的树(平衡二叉树):

以上就是一颗二叉平衡树,这样我们查找的最长时间为O(2),之前那棵不平衡的二叉搜索树却需要O(3)的时间,别看差距只有O(1),如果数据大了之后,差距可是非常的大的。
初始结构代码:
struct Node{
int data;
int r_high;
int l_high;
int high;
Node* lchild;
Node* rchild;
};
如何进行平衡操作:
思路1(调整输入顺序):
看我们上面的图,输入1,2,3后组成了一颗不平衡的二叉搜索树,但是如果我们输入2,1,3那么就可以解决这个问题,可以创建出高度平衡的二叉搜索树。
这个方法行不行呢?肯定是不行的呀,兄弟们啊!我们讲的是动态搜索啊,什么是动态啊,就是你在进行插入删除操作的之后,依旧可以进行查找,我们永远不知道输入来的下一个数是什么?更不能提前挑好输入顺序了呀,这个方法是不符合实际的,所以不能采用。
思路2(盯好BF):
我们这个思路就是要做好“盯好BF”,BF是什么呢?大家不要误解了啊,BF并不是男朋友的缩写哈,在计算机编程之中,BF就是每一个结点的高度,就是要我们盯紧这个二叉搜索树是不是高度平衡,如果是,那么不用管,如果不是,那么需要进行平衡操作,使其依旧保持高度平衡(并且符合二叉搜索树的基本性质:左子节点小于根节点,右子节点大于根节点)。
我们怎么求每一个节点的高度呢?我们可以编写一个函数来解决,就是一个递归还是,不断的前往其的左子节点、右子节点,如果不为空的话那么进行计数器倒推++,这样就可以求出左子树的高度和右子树的高度,对两者相减的绝对值进行判断,是不是高度平衡。
我们可以进行一次总结,看看二叉搜索树有哪些不平衡的的情形。
平衡二叉树不平衡的情形:
把需要重新平衡的结点叫做q,由于任意两个结点最多只有两个儿子,因此高度不平