AVL树

参考 skywang12345 http://www.cnblogs.com/skywang12345/p/3576969.html

AVL树的介绍

AVL树是根据它的发明者G.M. Adelson-Velsky和E.M. Landis命名的。
它是最先发明的自平衡二叉查找树,也被称为高度平衡树。相比于"二叉查找树",它的特点是:AVL树中任何节点的两个子树的高度最大差别为1。

上面的两张图片,左边的是AVL树,它的任何节点的两个子树的高度差别都<=1;而右边的不是AVL树,因为7的两颗子树的高度相差为2(以2为根节点的树的高度是3,而以8为根节点的树的高度是1)。

AVL树的查找、插入和删除在平均和最坏情况下都是O(logn)。
如果在AVL树中插入或删除节点后,使得高度之差大于1。此时,AVL树的平衡状态就被破坏,它就不再是一棵二叉树;为了让它重新维持在一个平衡状态,就需要对其进行旋转处理。学AVL树,重点的地方也就是它的旋转算法;在后文的介绍中,再来对它进行详细介绍。

AVL树的旋转

前面说过,如果在AVL树中进行插入或删除节点后,可能导致AVL树失去平衡。这种失去平衡的可以概括为4种姿态:LL(左左),LR(左右),RR(右右)和RL(右左)。下面给出它们的示意图:

上图中的4棵树都是"失去平衡的AVL树",从左往右的情况依次是:LL、LR、RL、RR。除了上面的情况之外,还有其它的失去平衡的AVL树,如下图:


上面的两张图都是为了便于理解,而列举的关于"失去平衡的AVL树"的例子。总的来说,AVL树失去平衡时的情况一定是LL、LR、RL、RR这4种之一,它们都由各自的定义:

(1) LL:LeftLeft,也称为"左左"。插入或删除一个节点后,根节点的左子树的左子树还有非空子节点,导致"根的左子树的高度"比"根的右子树的高度"大2,导致AVL树失去了平衡。
     例如,在上面LL情况中,由于"根节点(8)的左子树(4)的左子树(2)还有非空子节点",而"根节点(8)的右子树(12)没有子节点";导致"根节点(8)的左子树(4)高度"比"根节点(8)的右子树(12)"高2。

(2) LR:LeftRight,也称为"左右"。插入或删除一个节点后,根节点的左子树的右子树还有非空子节点,导致"根的左子树的高度"比"根的右子树的高度"大2,导致AVL树失去了平衡。
     例如,在上面LR情况中,由于"根节点(8)的左子树(4)的左子树(6)还有非空子节点",而"根节点(8)的右子树(12)没有子节点";导致"根节点(8)的左子树(4)高度"比"根节点(8)的右子树(12)"高2。

(3) RL:RightLeft,称为"右左"。插入或删除一个节点后,根节点的右子树的左子树还有非空子节点,导致"根的右子树的高度"比"根的左子树的高度"大2,导致AVL树失去了平衡。
     例如,在上面RL情况中,由于"根节点(8)的右子树(12)的左子树(10)还有非空子节点",而"根节点(8)的左子树(4)没有子节点";导致"根节点(8)的右子树(12)高度"比"根节点(8)的左子树(4)"高2。

(4) RR:RightRight,称为"右右"。插入或删除一个节点后,根节点的右子树的右子树还有非空子节点,导致"根的右子树的高度"比"根的左子树的高度"大2,导致AVL树失去了平衡。

LL旋转

LL失去平衡的情况,可以通过一次旋转让AVL树恢复平衡。如下图:

图中左边是旋转之前的树,右边是旋转之后的树。从中可以发现,旋转之后的树又变成了AVL树,而且该旋转只需要一次即可完成。
对于LL旋转,你可以这样理解为:LL旋转是围绕"失去平衡的AVL根节点"进行的,也就是节点k2;而且由于是LL情况,即左左情况,就用手抓着"左孩子,即k1"使劲摇。将k1变成根节点,k2变成k1的右子树,"k1的右子树"变成"k2的左子树"。

RR旋转

理解了LL之后,RR就相当容易理解了。RR是与LL对称的情况!RR恢复平衡的旋转方法如下:

图中左边是旋转之前的树,右边是旋转之后的树。RR旋转也只需要一次即可完成。

LR旋转

LR失去平衡的情况,需要经过两次旋转才能让AVL树恢复平衡。如下图:


第一次旋转是围绕"k1"进行的"RR旋转",第二次是围绕"k3"进行的"LL旋转"。

RL旋转

RL是与LR的对称情况!RL恢复平衡的旋转方法如下:

第一次旋转是围绕"k3"进行的"LL旋转",第二次是围绕"k1"进行的"RR旋转"。

C++代码

#include <iostream>
#include <algorithm>
using namespace std;

struct TreeNode{
	int key;
	TreeNode* left;
	TreeNode* right;
	TreeNode(int _key, TreeNode* _left, TreeNode* _right) :key(_key), left(_left), right(_right){}
};

int getHeight(TreeNode* T){
	if (T == NULL){
		return 0;
	}
	return max(getHeight(T->left), getHeight(T->right)) + 1;
}

TreeNode* LL(TreeNode* T){
	TreeNode* left = T->left;
	T->left = left->right;
	left->right = T;
	return left;
}


TreeNode* RR(TreeNode* T){
	TreeNode* right = T->right;
	T->right = right->left;
	right-> left = T;
	return right;
}

TreeNode* LR(TreeNode* T){
	T->left = RR(T->left);
	return LL(T);
}

TreeNode* RL(TreeNode* T){
	T->right = LL(T->right);
	return RR(T);
}

TreeNode* insert(TreeNode* T, int val)
{
	if (T == nullptr)
	{
		T = new TreeNode(val,nullptr,nullptr);
		return T;
	}
	
	if (val < T->key)
	{
		T->left = insert(T->left, val);
		if (getHeight(T->left) - getHeight(T->right) >= 2){
			
			if (val < T->left->key)
				T = LL(T);  //左左旋转
			else
				T = LR(T); //左右旋转
		}
	}
	else {
		T->right = insert(T->right, val);
		if (getHeight(T->right) - getHeight(T->left) >= 2){
			
			if (val > T->right->key)
				T = RR(T); //右右旋转  
			else
				T = RL(T); //右左旋转
		}
	}

	return T;
}

void preorder(TreeNode* T){
	if (T == nullptr)
		return;
	cout << T->key << " ";
	preorder(T->left);
	preorder(T->right);
}

int main(void)
{
	TreeNode* T = nullptr;
	for (size_t i = 0; i < 7; i++)
		T = insert(T, i+1);
	preorder(T);
	
}

  

posted @ 2016-10-28 13:53  WillWu  阅读(527)  评论(0编辑  收藏  举报