AVL 平衡树

  AVL是一种平衡二叉树,它通过对二叉搜索树中的节点进行旋转使得二叉搜索树达到平衡。AVL在所有的平衡二叉搜索树中具有最高的平衡性。

定义

    平衡二叉树或者为空树或者为满足如下性质的二叉搜索树:

  1. 左右子树的高度之差绝对值不超过1
  2. 左右子树仍然为平衡二叉树

    定义平衡因子 BF(x) = x的左子树高度 - x的右子树的高度。平衡二叉树的每个节点的平衡因子只能为-1, 0, 1.

维持平衡思想

    若二叉树当前为平衡状态,此时插入/删除一个新的节点,此时有可能造成二叉树不满足平衡条件,此时需要通过对节点进行旋转来使得二叉树达到平衡状态。从被插入/删除的节点开始向上查找,找到第一个不满足 |BF| <= 1的祖先节点P,此时对P和P的子节点(或P的子节点的子节点)进行旋转(可能分为下面的四种情况)。

旋转

    (1)LL型平衡旋转法 
    由于在A的左孩子B的左子树上插入结点F,使A的平衡因子由1增至2而失去平衡。故需进行一次顺时针旋转操作。 即将A的左孩子B向右上旋转代替A作为根结点,A向右下旋转成为B的右子树的根结点。而原来B的右子树则变成A的左子树。 
LL旋转

    (2)RR型平衡旋转法 
    由于在A的右孩子C 的右子树上插入结点F,使A的平衡因子由-1减至-2而失去平衡。故需进行一次逆时针旋转操作。即将A的右孩子C向左上旋转代替A作为根结点,A向左下旋转成为C的左子树的根结点。而原来C的左子树则变成A的右子树。 
RR旋转

    (3)LR型平衡旋转法 
    由于在A的左孩子B的右子数上插入结点F,使A的平衡因子由1增至2而失去平衡。故需进行两次旋转操作(先逆时针,后顺时针)。即先将A结点的左孩子B的右子树的根结点D向左上旋转提升到B结点的位置,然后再把该D结点向右上旋转提升到A结点的位置。即先使之成为LL型,再按LL型处理。 
LR旋转 
    如图中所示,即先将圆圈部分先调整为平衡树,然后将其以根结点接到A的左子树上,此时成为LL型,再按LL型处理成平衡型。

    (4)RL型平衡旋转法 
    由于在A的右孩子C的左子树上插入结点F,使A的平衡因子由-1减至-2而失去平衡。故需进行两次旋转操作(先顺时针,后逆时针),即先将A结点的右孩子C的左子树的根结点D向右上旋转提升到C结点的位置,然后再把该D结点向左上旋转提升到A结点的位置。即先使之成为RR型,再按RR型处理。 
RL旋转 
    如图中所示,即先将圆圈部分先调整为平衡树,然后将其以根结点接到A的左子树上,此时成为RR型,再按RR型处理成平衡型。

实现(c++)

#include<iostream>
using namespace std;
#define MAX(a, b) a > b? a:b
struct TreeNode{
	int data;
	TreeNode* child[2];
	int size;
	int height;
	int count;
	TreeNode(int val){
		data = val;
		size = count = height = 1;
		child[0] = child[1] = NULL;
	}
	void Update(){
		size = count;
		height = 1;
		if (child[0]){
			size += child[0]->size;
			height = MAX(height, 1 + child[0]->height);
		}
		if (child[1]){
			size += child[1]->size;
			height = MAX(height, 1 + child[1]->height);
		}
	}
};

struct AVL{
	TreeNode* root;
	AVL() :root(NULL){};

	int GetHeight(TreeNode* node){
		if (!node)
			return 0;
		return node->height;
	}
	int GetSize(TreeNode* node){
		if (!node)
			return 0;
		return node->size;
	}

	//注意这里使用指针的引用
	void Rotate(TreeNode*& node, int dir){
		TreeNode* ch = node->child[dir];
		node->child[dir] = ch->child[!dir];
		ch->child[!dir] = node;
		node->Update();
		node = ch;
	}
	void Maintain(TreeNode*& node){
		if (!node){
			return;
		}
		int bf = GetHeight(node->child[0]) - GetHeight(node->child[1]);
		if (bf >= -1 && bf <= 1){
			return;
		}
		if (bf == 2){
			int bf2 = GetHeight(node->child[0]->child[0]) - GetHeight(node->child[0]->child[1]);
			if (bf2 == 1){ //左左旋转
				Rotate(node, 0);
			}
			else if (bf2 == -1){ //左右旋转
				Rotate(node->child[0], 1);
				Rotate(node, 0);
			}
		}
		else if (bf == -2){
			int bf2 = GetHeight(node->child[1]->child[0]) - GetHeight(node->child[1]->child[1]);
			if (bf2 == 1){ //右左旋转
				Rotate(node, 1);
			}
			else if (bf2 == -1){ //右右旋转
				Rotate(node->child[1], 0);
				Rotate(node, 1);
			}
		}

	}
	void Insert(TreeNode*& node, int val){
		if (!node){
			node = new TreeNode(val);
		}
		else if (node->data == val){
			node->count++;
		}
		else{
			int dir = node->data < val;
			Insert(node->child[dir], val);
		}
		//维持树的平衡
		Maintain(node);
		//更新节点
		node->Update();
	}

	//注意参数为指针的引用
	void Delete(TreeNode*& node, int val){
		if (!node){
			return;
		}else if (node->data == val){
			if (node->child[0] && node->child[1]){
				int dir = GetHeight(node->child[0]) < GetHeight(node->child[1]);
				//将子树中较高的那棵,旋转
				Rotate(node, dir);
				//递归调用delete,直到叶子节点才进行真正的删除
				Delete(node->child[! dir], val);
			}
			else{
				TreeNode* tmp_node = NULL;
				if (node->child[0]){
					tmp_node = node->child[0];
				}
				else if (node->child[1]){
					tmp_node = node->child[1];
				}
				delete node;
				node = tmp_node; //使用引用
			}
		}
		else{
			int dir = node->data < val;
			Delete(node->child[dir], val);
		}
		Maintain(node);	 //维持平衡
		node->Update();	//更新节点
	}
	int GetKth(TreeNode* node, int k){
		while (node){
			if (! node->child[0]){
				if (k <= node->count){
					return node->data;
				}
				else{
					k -= node->count;
					node = node->child[1];
				}
			}
			else{
				if (node->child[0]->size < k && node->child[0]->size + node->count >= k){
					return node->data;
				}
				else if (node->child[0]->size > k){
					node = node->child[0];
				}
				else{
					k -= (node->child[0]->size + node->count);
					node = node->child[1];
				}
			}
		}
		return -1;
	}
};

 参考: 
平衡树 balanced binary tree (AVL tree)   
AVL树 模板

posted @ 2015-08-10 16:56  农民伯伯-Coding  阅读(270)  评论(0编辑  收藏  举报