高级搜索树-AVL树

AVL树是平衡二叉搜索树中的一种,在渐进意义下,AVL树可以将高度始终控制在O(log n) 以内,以保证每次查找、插入和删除操作均可以在O(log n)的时间内完成。

平衡因子

定义任一结点v的平衡因子(balance factor)为其左右子树的高度差

balfac(v) = height(v->lc) - height(v->rc)

AVL树即平衡因子受限的二叉搜索树—————各结点平衡因子的绝对值不超过1


template<typename T>
inline bool AVLTree<T>::balanced(AVLNodePos(T) &cur) {
	int lh = 0, rh = 0;
	if (HasLChild(cur))
		lh = cur->lc->height;
	if (HasRChild(cur))
		rh = cur->rc->height;
	if ((lh - rh)*(lh - rh) > 1)
		return false;
	return true;
}

AVL树节点和AVL树的定义

  1. AVL节点AVLNode的定义
template<typename T>
struct AVLNode {
public:
	T key;
	int height;
	AVLNodePos(T) pa;//pa -- parent
	AVLNodePos(T)  lc;//lc -- left child
	AVLNodePos(T)  rc;//rc -- right child
	//构造函数
	AVLNode(): height(0), pa(NULL), lc(NULL), rc(NULL) {}
	AVLNode(T elem, int height = 0, AVLNodePos(T)	 pa = NULL, AVLNodePos(T) lc = NULL, AVLNodePos(T)	 rc = NULL) :
		key(elem), height(height), pa(pa), lc(lc), rc(rc) { }
};

  1. AVL树AVLTree的定义如下

template<typename T>
class AVLTree {
private:
	AVLNodePos(T)	root;		//树根
public:
	//构造函数和析构函数
	AVLTree():root(NULL){}
	~AVLTree() {}

	//只读函数
	int height() { return Height(root); }
	//遍历函数
	void preOrder();	//前序遍历
	void inOrder();		//中序遍历
	void postOrder();	//后序遍历
	//操作函数
	AVLNodePos(T)	search(const T	 &key);		//查找函数,若存在值为key的节点返回相应节点,若不存在则返回NULL
	AVLNodePos(T) insert(const T &key);		//插入值为key的节点
	bool remove(const T &key);	//移除值为key的节点

private:
	bool balanced(AVLNodePos(T) &cur);	//判断cur节点是否平衡
	void upDataHeight(AVLNodePos(T) &cur);	//更新节点cur的高度
	void preOrder(AVLNodePos(T) &cur);		//以cur节点为root进行前序遍历
	void inOrder(AVLNodePos(T) &cur);		//以cur节点为root进行中序遍历
	void postOrder(AVLNodePos(T) &cur);	//以cur节点为root进行后序遍历
	AVLNodePos(T) searchIn(const T & key, AVLNodePos(T) cur, AVLNodePos(T)& hot);	//以cur节点为root查找值为key的节点,hot为返回节点的父节点
	AVLNodePos(T)	tallerChild(AVLNodePos(T) &g);	//返回g高度更高的孩子
	AVLNodePos(T) connect34(AVLNodePos(T) a, AVLNodePos(T) b, AVLNodePos(T) c,	//根据 "3"+"4"法则对子树进行调整
		AVLNodePos(T) T0, AVLNodePos(T) T1, AVLNodePos(T) T2, AVLNodePos(T) T3);
	AVLNodePos(T)	adjustNode(AVLNodePos(T)& cur);	//调整失衡节点cur,返回调整后得到局部子树的root,并将调整后子树接入原树
};

失衡调整

AVL树和常规二叉搜索树一样也支持插入、删除等动态修改操作,但是经过这类操作之后节点的高度可能发生变化,以至于不再满足AVL树的条件。为此要定义相关使得搜索树平衡的调整算法。只需在每次动态操作后利用balanced()函数判断当前节点是否平衡,在找到第一个失衡节点g后,找到g高度更高的孩子p和p高度更高的孩子s这三个节点,根据相应g,p,s的关系能找到四棵子树T0,T1,T2,T3,利用 3 + 4 重构法则就能统一调整算法

//根据 "3"+"4"法则对子树进行调整
template<typename T>
AVLNodePos(T) AVLTree<T>::connect34(
	AVLNodePos(T) a, AVLNodePos(T) b, AVLNodePos(T) c,
	AVLNodePos(T) T0, AVLNodePos(T) T1, AVLNodePos(T) T2, AVLNodePos(T) T3)
{																					//最终实现效果如下:
	a->lc = T0;	if (T0)	T0->pa = a;								//							b
	a->rc = T1;	if (T1)	T1->pa = a;								//						/		\ 
	c->lc = T2;	if (T2)	T2->pa = c;								//                  a				 c
	c->rc = T3;	if (T3)	T3->pa = c;								//				/		 \		  /     \ 
	b->lc = a;		b->rc = c;									//           T0          T1     T2       T3
	a->pa = b;	c->pa = b;
	b->pa = NULL;
	upDataHeight(a); 
	upDataHeight(c); 
	upDataHeight(b);	//更新高度
	return b;	//返回b
}

//调整失衡节点cur,返回调整后得到局部子树的root,并将调整后子树接入原树
template<typename T>
AVLNodePos(T) AVLTree<T>::adjustNode(AVLNodePos(T)	&g) {
	//一旦发现失衡	找到g,p,s 三个节点				//g --grandfa
	AVLNodePos(T)  p = tallerChild(g);	//p --parent
	AVLNodePos(T)  s = tallerChild(p);		//s --son
	AVLNodePos(T)	gg = g->pa;	//gg -- g's parent
	if (IsLChild(s) && IsLChild(p))		//left -- left 
		g = connect34(s, p, g, s->lc, s->rc, p->rc, g->rc);
	else if (IsRChild(s) && IsLChild(p))	//right -- left
		g = connect34(p, s, g, p->lc, s->lc, s->rc, g->rc);
	else if (IsRChild(s) && IsRChild(p))	//right -- right
		g = connect34(g, p, s, g->lc, p->lc, s->lc, s->rc);
	else if (IsLChild(s) && IsRChild(p))	//left -- left
		g = connect34(g, s, p, g->lc, s->lc, s->rc, p->rc);

	//将调整后子树接回原树
	if (!gg)		root = g;//	gg为NULL说明g为root,更新root
	else {	//连接gg和 g
		if (gg->key > g->key) {//作为左子树接入
			gg->lc = g;
			g->pa = gg;
		}
		else {//作为右子树接入
			gg->rc = g;
			g->pa = gg;
		}
	}
	upDataHeight(gg);//g的高度已经在connect34时更新,故更新连接g后的gg高度
	return g;
}

插入和删除操作

插入和删除操作同搜索二叉树一样,只是每一次都要节点检查是否平衡,如果失衡则进行调整

//AVLNodePos(T) searchIn(const T & key, AVLNodePos(T) cur, AVLNodePos(T)& hot);以cur节点为root查找值为key的节点,hot为返回节点的父节点
//插入值为key的节点
template<typename T>
AVLNodePos(T) AVLTree<T>::insert(const T & key)
{
	AVLNodePos(T)	cur_pa=NULL;
	AVLNodePos(T) x = searchIn(key, root, cur_pa);
	if (x)	return x;	//已经存在值为key的节点	
	//否则确认key不存在
	if (!root)
		x = root = new AVLNode<T>(key);
	else {
		//连接节点
		x = new AVLNode<T>(key,0,cur_pa);
		if (x->key > cur_pa->key)
			cur_pa->rc = x;
		else
			cur_pa->lc = x;
		upDataHeight(x);	//更新高度
	}
	for (AVLNodePos(T) g = cur_pa; g; g = g->pa) {	//从	插入节点的父节点开始向上检查
		if (!balanced(g)) {//若g失衡
			adjustNode(g);//调整以g为root的局部子树
			break;	//g复平衡后,局部子树高度必然复原,其祖先亦如此,故调整可到此结束
		}else {//否则g平衡
			upDataHeight(g);		//更新高度
		}
	}
	return x;	//返回新插入节点位置
}

//移除值为key的节点
template<typename T>
inline bool AVLTree<T>::remove(const T & key)
{
	AVLNodePos(T)	x = search(key);
	if (!x)	
		return false;//不存在值为key的节点
	AVLNodePos(T)	w = x;	//w是实际被摘除节点
	if (!HasLChild(x)) {//	如果x没有左子树,用右子树代替x
		if (IsRoot(x))
			root = x->rc;
		else {
			if (IsLChild(x))	x->pa->lc = x->rc;
			else x->pa->rc = x->rc;
		}
	}
	else if (!HasRChild(x)) {//如果x没有右子树, 用左子树替代
		if (IsRoot(x))
			root = x->lc;
		else {
			if (IsLChild(x))	x->pa->lc = x->lc;
			else x->pa->rc = x->lc;
		}
	}else {	//否则有左右子树
		//取w为x的直接后继
		w = x->rc;
		while (HasLChild(w))
			w = w->lc;
		//交换数据
		T tmp = x->key;
		x->key = w->key;
		w->key = tmp;
		if (HasRChild(w)) 
			w->rc->pa = w->pa;
		if (w->pa == x)		// 注意 w为x的右子这种情况   
			x->rc = w->rc;		
		else
			w->pa->lc = w->rc;
		
	}
		upDataHeight(w->pa);
	for (AVLNodePos(T) g = w->pa; g; g = g->pa) {	//从succ的父节点开始向上检查
		if (!balanced(g)) {//若g失衡
			g=adjustNode(g);//调整以g为root的局部子树
			//不同于插入操作,删除操作造成的失衡可能会传播
		}
		else {//否则g平衡
			upDataHeight(g);		//更新高度
		}
	}
	delete w;//摘除w
	return true;
}

完整源码

代码参考《数据结构(c++语言版)》--清华大学邓俊辉

"AVLTree_Declaration.h"

//#include"pch.h"
#include<iostream>
#ifndef  _AVL_TREE_DECLARATION_H
#define  _AVL_TREE_DECLARATION_H

#define AVLNodePos(T)	AVLNode<T> *
//宏定义
#define IsRoot(x)		( !((x)->pa) )
#define IsLChild(x)	( !(IsRoot(x)	) && (x)==(x)->pa->lc)
#define IsRChild(x)	( !(IsRoot(x)	) && (x)==(x)->pa->rc)
#define HasLChild(x)	((x)->lc )
#define HasRChild(x)	((x)->rc )
#define HasChild(x)		(HasLChild(x) || HasRChild(x))
#define HasBothChild(x)	(HasRChild(x) && HasLChild(x) )
#define IsLeaf(x)		(! HasChild(x) )
#define Height(x)		( (x)==NULL? 0: (x)->height )	//x的高度
//AVLNode 定义
template<typename T>    
struct AVLNode {
public:
	T key;
	int height;
	AVLNodePos(T) pa;//pa -- parent
	AVLNodePos(T)  lc;//lc -- left child
	AVLNodePos(T)  rc;//rc -- right child
	//构造函数
	AVLNode(): height(0), pa(NULL), lc(NULL), rc(NULL) {}
	AVLNode(T elem, int height = 0, AVLNodePos(T)	 pa = NULL, AVLNodePos(T) lc = NULL, AVLNodePos(T)	 rc = NULL) :
		key(elem), height(height), pa(pa), lc(lc), rc(rc) { }
};
//AVLTree 定义
template<typename T>
class AVLTree {
private:
	AVLNodePos(T)	root;		//树根
public:
	//构造函数和析构函数
	AVLTree():root(NULL){}
	~AVLTree() {}

	//只读函数
	int height() { return Height(root); }
	//遍历函数
	void preOrder();	//前序遍历
	void inOrder();		//中序遍历
	void postOrder();	//后序遍历
	//操作函数
	AVLNodePos(T)	search(const T	 &key);		//查找函数,若存在值为key的节点返回相应节点,若不存在则返回NULL
	AVLNodePos(T) insert(const T &key);		//插入值为key的节点
	bool remove(const T &key);	//移除值为key的节点

private:
	bool balanced(AVLNodePos(T) &cur);	//判断cur节点是否平衡
	void upDataHeight(AVLNodePos(T) &cur);	//更新节点cur的高度
	void preOrder(AVLNodePos(T) &cur);		//以cur节点为root进行前序遍历
	void inOrder(AVLNodePos(T) &cur);		//以cur节点为root进行中序遍历
	void postOrder(AVLNodePos(T) &cur);	//以cur节点为root进行后序遍历
	AVLNodePos(T) searchIn(const T & key, AVLNodePos(T) cur, AVLNodePos(T)& hot);	//以cur节点为root查找值为key的节点,hot为返回节点的父节点
	AVLNodePos(T)	tallerChild(AVLNodePos(T) &g);	//返回g高度更高的孩子
	AVLNodePos(T) connect34(AVLNodePos(T) a, AVLNodePos(T) b, AVLNodePos(T) c,	//根据 "3"+"4"法则对子树进行调整
		AVLNodePos(T) T0, AVLNodePos(T) T1, AVLNodePos(T) T2, AVLNodePos(T) T3);
	AVLNodePos(T)	adjustNode(AVLNodePos(T)& cur);	//调整失衡节点cur,返回调整后得到局部子树的root,并将调整后子树接入原树
};
#endif

"AVLTree_Define.cpp"

//具体实现
//#include"pch.h"
#include "AVLTree_Declaration.h"
#include<iostream>

#ifndef _AVL_TREE_DEFINE_H
#define _AVL_TREE_DEFINE_H

template<typename T>
inline void AVLTree<T>::preOrder(AVLNodePos(T) & cur)
{
	if (!cur)	return;
	std::cout << cur->key << " ";
	preOrder(cur->lc);
	preOrder(cur->rc);
}

template<typename T>
inline void AVLTree<T>::inOrder(AVLNodePos(T) & cur)
{
	if (!cur)	return;
	inOrder(cur->lc);
	std::cout << cur->key << " ";
	inOrder(cur->rc);
}

template<typename T>
inline void AVLTree<T>::postOrder(AVLNodePos(T)& cur)
{
	if (!cur)	return;
	postOrder(cur->lc);
	postOrder(cur->rc);
	std::cout << cur->key << " ";
}

template<typename T>
inline void AVLTree<T>::preOrder()
{
	preOrder(root);
}

template<typename T>
inline void AVLTree<T>::inOrder()
{
	inOrder(root);
}

template<typename T>
inline void AVLTree<T>::postOrder()
{
	postOrder(root);
}
//判断cur节点是否平衡
template<typename T>
inline bool AVLTree<T>::balanced(AVLNodePos(T) &cur) {
	int lh = 0, rh = 0;
	if (HasLChild(cur))
		lh = cur->lc->height;
	if (HasRChild(cur))
		rh = cur->rc->height;
	if ((lh - rh)*(lh - rh) > 1)
		return false;
	return true;
}
//返回g高度更高的孩子
template<typename T>
inline AVLNodePos(T)	AVLTree<T>::tallerChild(AVLNodePos(T) &g) {
	if (HasBothChild(g)) {
		return (g->lc->height >= g->rc->height ? g->lc : g->rc);
	}
	else if (HasLChild(g))
		return g->lc;
	else if (HasRChild(g))
		return g->rc;
	return NULL;
}
//更新节点cur的高度
template<typename T>
inline void AVLTree<T>::upDataHeight(AVLNodePos(T) &	p)
{
	if (!p)	return;
	int tmp = p->height;
	if (IsLeaf(p))
		p->height = 1;
	else if (HasBothChild(p))
		p->height = (p->lc->height > p->rc->height) ? p->lc->height + 1 : p->rc->height + 1;
	else if (HasLChild(p))
		p->height = p->lc->height + 1;
	else if (HasRChild(p))
		p->height = p->rc->height + 1;

	return;
}

//以cur节点为root查找值为key的节点,hot为返回节点的父节点
template<typename T>
inline AVLNodePos(T) AVLTree<T>::searchIn(const T & key, AVLNodePos(T) cur, AVLNodePos(T)& hot)
{
	if (!cur || key == cur->key)	return cur;
	hot = cur;
	return searchIn(key, (key < cur->key ? cur->lc : cur->rc), hot);
}

//查找函数,若存在值为key的节点返回相应节点,若不存在则返回NULL
template<typename T>
inline AVLNodePos(T) AVLTree<T>::search(const T & key)
{
	AVLNodePos(T) hot = NULL;
	return searchIn(key, root, hot);
}

//根据 "3"+"4"法则对子树进行调整
template<typename T>
AVLNodePos(T) AVLTree<T>::connect34(
	AVLNodePos(T) a, AVLNodePos(T) b, AVLNodePos(T) c,
	AVLNodePos(T) T0, AVLNodePos(T) T1, AVLNodePos(T) T2, AVLNodePos(T) T3)
{																					//最终实现效果如下:
	a->lc = T0;	if (T0)	T0->pa = a;								//							b
	a->rc = T1;	if (T1)	T1->pa = a;								//						/		\ 
	c->lc = T2;	if (T2)	T2->pa = c;								//                  a				 c
	c->rc = T3;	if (T3)	T3->pa = c;								//				/		 \		  /     \ 
	b->lc = a;		b->rc = c;									//             T0        T1      T2      T3
	a->pa = b;	c->pa = b;
	b->pa = NULL;
	upDataHeight(a); 
	upDataHeight(c); 
	upDataHeight(b);	//更新高度
	return b;	//返回b
}

//调整失衡节点cur,返回调整后得到局部子树的root,并将调整后子树接入原树
template<typename T>
AVLNodePos(T) AVLTree<T>::adjustNode(AVLNodePos(T)	&g) {
	//一旦发现失衡	找到g,p,s 三个节点				//g --grandfa
	AVLNodePos(T)  p = tallerChild(g);	//p --parent
	AVLNodePos(T)  s = tallerChild(p);		//s --son
	AVLNodePos(T)	gg = g->pa;	//gg -- g's parent
	if (IsLChild(s) && IsLChild(p))		//left -- left 
		g = connect34(s, p, g, s->lc, s->rc, p->rc, g->rc);
	else if (IsRChild(s) && IsLChild(p))	//right -- left
		g = connect34(p, s, g, p->lc, s->lc, s->rc, g->rc);
	else if (IsRChild(s) && IsRChild(p))	//right -- right
		g = connect34(g, p, s, g->lc, p->lc, s->lc, s->rc);
	else if (IsLChild(s) && IsRChild(p))	//left -- left
		g = connect34(g, s, p, g->lc, s->lc, s->rc, p->rc);

	//将调整后子树接回原树
	if (!gg)		root = g;//	gg为NULL说明g为root,更新root
	else {	//连接gg和 g
		if (gg->key > g->key) {//作为左子树接入
			gg->lc = g;
			g->pa = gg;
		}
		else {//作为右子树接入
			gg->rc = g;
			g->pa = gg;
		}
	}
	upDataHeight(gg);//g的高度已经在connect34时更新,故更新连接g后的gg高度
	return g;
}

//插入值为key的节点
template<typename T>
AVLNodePos(T) AVLTree<T>::insert(const T & key)
{
	AVLNodePos(T)	cur_pa=NULL;
	AVLNodePos(T) x = searchIn(key, root, cur_pa);
	if (x)	return x;	//已经存在值为key的节点	
	//否则确认key不存在
	if (!root)
		x = root = new AVLNode<T>(key);
	else {
		//连接节点
		x = new AVLNode<T>(key,0,cur_pa);
		if (x->key > cur_pa->key)
			cur_pa->rc = x;
		else
			cur_pa->lc = x;
		upDataHeight(x);	//更新高度
	}
	for (AVLNodePos(T) g = cur_pa; g; g = g->pa) {	//从	插入节点的父节点开始向上检查
		if (!balanced(g)) {//若g失衡
			adjustNode(g);//调整以g为root的局部子树
			break;	//g复平衡后,局部子树高度必然复原,其祖先亦如此,故调整可到此结束
		}else {//否则g平衡
			upDataHeight(g);		//更新高度
		}
	}
	return x;	//返回新插入节点位置
}

//删除值为key的节点
template<typename T>
inline bool AVLTree<T>::remove(const T & key)
{
	AVLNodePos(T)	x = search(key);
	if (!x)	
		return false;//不存在值为key的节点
	AVLNodePos(T)	w = x;	//w是实际被摘除节点
	if (!HasLChild(x)) {//	如果x没有左子树,用右子树代替x
		if (IsRoot(x))
			root = x->rc;
		else {
			if (IsLChild(x))	x->pa->lc = x->rc;
			else x->pa->rc = x->rc;
		}
	}
	else if (!HasRChild(x)) {//如果x没有右子树, 用左子树替代
		if (IsRoot(x))
			root = x->lc;
		else {
			if (IsLChild(x))	x->pa->lc = x->lc;
			else x->pa->rc = x->lc;
		}
	}else {	//否则有左右子树
		//取w为x的直接后继
		w = x->rc;
		while (HasLChild(w))
			w = w->lc;
		//交换数据
		T tmp = x->key;
		x->key = w->key;
		w->key = tmp;
		if (HasRChild(w)) 
			w->rc->pa = w->pa;
		if (w->pa == x)		// 注意 w为x的右子这种情况   
			x->rc = w->rc;		
		else
			w->pa->lc = w->rc;
		
	}
		upDataHeight(w->pa);
	for (AVLNodePos(T) g = w->pa; g; g = g->pa) {	//从succ的父节点开始向上检查
		if (!balanced(g)) {//若g失衡
			g=adjustNode(g);//调整以g为root的局部子树
			//不同于插入操作,删除操作造成的失衡可能会传播
		}
		else {//否则g平衡
			upDataHeight(g);		//更新高度
		}
	}
	delete w;//摘除w
	return true;
}


#endif

"main.cpp"

// main.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include <iostream>
#include"AVLTree_Define.h"
#include"AVLTree_Declaration.h"
using namespace std;
int main()
{
	AVLTree<int> t;
	int n;
	cout << "insert number:";
	cin >> n;
	cout << "insert:" ;
	for (int i = 0; i < n; i++) {
		int tmp;
		cin >> tmp;
		t.insert(tmp);
	}
	cout << "PreOrder:";
	t.preOrder();
	cout << endl;
	cout << "InOrder:";
	t.inOrder();
	cout << endl;
	cout << "PostOrder:";
	t.postOrder();
	cout << endl;
	cout << "remove number:";
	cin >>n;
	cout << "remove:";
	for (int i = 0; i < n; i++) {
		int tmp;
		cin >> tmp;
		t.remove(tmp);
	}
	cout << "PreOrder:";
	t.preOrder();
	cout << endl;
	cout << "InOrder:";
	t.inOrder();
	cout << endl;
	cout << "PostOrder:";
	t.postOrder();
	cout << endl;
	return 0;
}


posted @ 2020-06-06 17:28  海物chinono  阅读(160)  评论(0)    收藏  举报