数据结构实现 10.1:AVL树(C++版)

1. 概念及基本框架

AVL树 (即自平衡树)是一种二分搜索树,AVL 树要求每个结点的左右子树的树高度差不超过 1

AVL树

因为在二分搜索树中,不管二叉树左右子树的高度,所以二分搜索树的最坏情况可以退化成链表。所以这里我们需要对二分搜索树进行适当的修正,提高效率。
与二分搜索树类似,我们先给出AVL树的结点类:

template <typename K, typename V>
class AVLNode{
public:
	AVLNode(K key, V value){
		this->key = key;
		this->value = value;
		height = 1;
		left = NULL;
		right = NULL;
	}
public:
	K key;
	V value;
	int height;
	AVLNode<K, V> *left;
	AVLNode<K, V> *right;
};

这里我们增加了高度变量,用来记录每个结点的当前高度。
下面给出AVL树大体框架:

template <typename K, typename V>
class AVLTree{
public:
	AVLTree(){
		root = NULL;
		m_size = 0;
	}
	...
private:
	AVLNode<K, V> *root;
	int m_size;
};

与二分搜索树十分类似,所以这里不再赘述。
接下来我们就对AVL树的增加、删除、查找、遍历以及一些其他基本操作用代码去实现。

2. 基本操作程序实现

2.1 增加操作

既然AVL树是二分搜索树的一种,所以其基本实现代码与二分搜索树类似,我们直接给出:

template <typename K, typename V>
class AVLTree{
public:
	...
	//增加操作
	void add(K key, V value);
	...
private:
	AVLNode<K, V>* add(AVLNode<K, V>* node, K key, V value);
	...
};

类外实现代码:

template <typename K, typename V>
void AVLTree<K, V>::add(K key, V value){
	root = add(root, key, value);
}
template <typename K, typename V>
AVLNode<K, V>* AVLTree<K, V>::add(AVLNode<K, V>* node, K key, V value){
	if (node == NULL){
		m_size++;
		return new AVLNode<K, V>(key, value);
	}
	else if (key < node->key){
		node->left = add(node->left, key, value);
	}
	else if (key > node->key){
		node->right = add(node->right, key, value);
	}
	else if (key == node->key){
		node->value = value;
		return node;
	}
	//计算平衡因子
	node->height = max(getHeight(node->left), getHeight(node->right)) + 1;
	int balanceFactor = getBalanceFactor(node);
	//平衡维护
	if (balanceFactor > 1 && getBalanceFactor(node->left) >= 0){
		return rightRotate(node);
	}
	else if (balanceFactor < -1 && getBalanceFactor(node->right) <= 0){
		return leftRotate(node);
	}
	else if (balanceFactor > 1 && getBalanceFactor(node->left) < 0){
		node->left = leftRotate(node->left);
		return rightRotate(node);
	}
	else if (balanceFactor < -1 && getBalanceFactor(node->right) > 0){
		node->right = rightRotate(node->right);
		return leftRotate(node);
	}
	return node;
}

这里需要注意的是在进行完增加操作之后我们需要进行一定的修正。修正之前需要得到一些基础信息,用下面几个函数来实现。
max 返回其中的最大值。
getHeight 返回一个结点的高度。
getBalanceFactor 返回一个结点的平衡因子。(用左子树高度减去右子树高度)
leftRotaterightRotate 分别表示左旋、右旋,具体实现方法后面详细讲述。
前面三个函数代码如下:

template <typename K, typename V>
class AVLTree{
	...
private:
	...
	int max(int a, int b){ return a > b ? a : b; }
	...
};
template <typename K, typename V>
int AVLTree<K, V>::getHeight(AVLNode<K, V>* node){
	if (node == NULL){
		return 0;
	}
	return node->height;
}
template <typename K, typename V>
int AVLTree<K, V>::getBalanceFactor(AVLNode<K, V>* node){
	int lHeight = 0, rHeight = 0;
	if (node == NULL){
		return 0;
	}
	if (node->left != NULL){
		lHeight = node->left->height;
	}
	if (node->right != NULL){
		rHeight = node->right->height;
	}
	return lHeight - rHeight;
}

接下来我们详细讲述修正的左旋和右旋函数。
首先我们分情况,当一个新增加的结点需要修正,一定是其祖父结点一脉单传到了新结点。那么,作为一个新增加的结点,有两种可能,在父结点的左/右,而父结点也可以在祖父节点的左/右,所以一共有四种。我们可以简称为左左、左右、右左、右右四种情况。

2.1.1 左左

左左

注:这里每个结点都挂有子树(子树可以为空),这些子树本身已经是平衡的了(下同,这里考虑的是修正自下而上递推到这里),我们可以忽略。
如上图,结点 C 左右子树平衡因子为 2 > 1 ,所以需要修正,修正过程如下:
1.新建一个临时结点 P 指向 B 的右子结点。
2.把 C 作为 B 的右子结点。
3.把 P 作为 C 的左子结点。
4.将结点 B 返回。
经过旋转,结点的数据依旧满足二分搜索树的基本性质,所以可以旋转,这里结点 B 和结点 C 发生了 右旋
图中虚线圈住的结点表示实际发生了旋转的结点,橙色(紫色)的线表示发生变化的支,黄色的线表示返回结点的指向,后面不再赘述。
右旋代码实现如下:

template <typename K, typename V>
AVLNode<K, V>* AVLTree<K, V>::rightRotate(AVLNode<K, V>* node){
	AVLNode<K, V>* res = node->left;
	AVLNode<K, V>* p = res->right;
	res->right = node;
	node->left = p;
	//维护平衡
	node->height = max(getHeight(node->left), getHeight(node->right)) + 1;
	res->height = max(getHeight(res->left), getHeight(res->right)) + 1;
	return res;
}

2.1.2 右右

在这里插入图片描述

如上图,结点 A 左右子树平衡因子为 | - 2 | > 1 ,所以需要修正,修正过程如下:
1.新建一个临时结点 P 指向 B 的左子结点。
2.把 A 作为 B 的左子结点。
3.把 P 作为 A 的右子结点。
4.将结点 B 返回。
经过旋转,结点的数据依旧满足二分搜索树的基本性质,所以可以旋转,这里结点 A 和结点 B 发生了 左旋
下面分析两种比较复杂的情况,左右和右左。
左旋代码实现如下:

template <typename K, typename V>
AVLNode<K, V>* AVLTree<K, V>::leftRotate(AVLNode<K, V>* node){
	AVLNode<K, V>* res = node->right;
	AVLNode<K, V>* p = res->left;
	res->left = node;
	node->right = p;
	//维护平衡
	node->height = max(getHeight(node->left), getHeight(node->right)) + 1;
	res->height = max(getHeight(res->left), getHeight(res->right)) + 1;
	return res;
}

2.1.3 左右

左右

如上图,结点 C 左右子树平衡因子为 2 > 1 ,所以需要修正,修正过程如下:
1.把结点 A 和结点 B 左旋。(这时可看作右右情况)
2.把结点 B 和结点 C 右旋。(这时是左左情况)
3.返回结点 B
经过旋转,结点的数据依旧满足二分搜索树的基本性质。

2.1.4 右左

右左

如上图,结点 A 左右子树平衡因子为 | - 2 | > 1 ,所以需要修正,修正过程如下:
1.把结点 B 和结点 C 右旋。(这时可看作左左情况)
2.把结点 A 和结点 B 左旋。(这时是右右情况)
3.返回结点 B
经过旋转,结点的数据依旧满足二分搜索树的基本性质。

2.1.5 增加操作修正总结

1.左左:右旋祖父结点和父结点,返回父结点。
2.右右:左旋祖父结点和父结点,返回父结点。
3.左右:左旋父结点和子结点,右旋祖父结点和新的父结点(即原来的子结点),返回新的父结点(即原来的子结点)。
4.右左:右旋父结点和子结点,左旋祖父结点和新的父结点(即原来的子结点),返回新的父结点(即原来的子结点)。
左左右,右右左,兄做侄,祖成兄,父替祖,返林中。
左右左,成左左,右左右,成右右,人虽新,法依旧。

2.2 删除操作

删除操作与二分搜索树类似,只是增加修正过程:

template <typename K, typename V>
class AVLTree{
public:
	...
	//删除操作
	void remove(K key);
	...
private:
	...
	AVLNode<K, V>* remove(AVLNode<K, V>* node, K key);
	...
};

类外实现如下:

template <typename K, typename V>
void AVLTree<K, V>::remove(K key){
	root = remove(root, key);
}
template <typename K, typename V>
AVLNode<K, V>* AVLTree<K, V>::remove(AVLNode<K, V> *node, K key){
	if (node == NULL){
		return node;
	}
	AVLNode<K, V> *resNode = node;
	if (key < node->key){
		node->left = remove(node->left, key);
	}
	else if (key > node->key){
		node->right = remove(node->right, key);
	}
	else if (key == node->key){
		if (node->left == NULL){
			AVLNode<K, V> *rightNode = node->right;
			delete node;
			m_size--;
			resNode = rightNode;
		}
		else if (node->right == NULL){
			AVLNode<K, V> *leftNode = node->left;
			delete node;
			m_size--;
			resNode = leftNode;
		}
		else{
			AVLNode<K, V> *minNode = node->right;
			for (; minNode->left; minNode = minNode->left);
			minNode->right = remove(node->right, minNode->key);
			minNode->left = node->left;
			node->left = node->right = NULL;
			resNode = minNode;
		}
	}
	if (resNode == NULL){
		return NULL;
	}
	//计算平衡因子
	resNode->height = max(getHeight(resNode->left), getHeight(resNode->right)) + 1;
	int balanceFactor = getBalanceFactor(resNode);
	//平衡维护
	if (balanceFactor > 1 && getBalanceFactor(resNode->left) >= 0){
		return rightRotate(resNode);
	}
	else if (balanceFactor < -1 && getBalanceFactor(resNode->right) <= 0){
		return leftRotate(resNode);
	}
	else if (balanceFactor  > 1 && getBalanceFactor(resNode->left) < 0){
		resNode->left = leftRotate(resNode->left);
		return rightRotate(resNode);
	}
	else if (balanceFactor < -1 && getBalanceFactor(resNode->right) > 0){
		resNode->right = rightRotate(resNode->right);
		return leftRotate(resNode);
	}
	return resNode;
}

2.2.1 左右均空

1

2.2.2 左空右不空

3

2.2.3 左不空右空

2

2.2.4 左右均不空

4

2.2.5 删除操作修正总结

1.左右均空:直接删除该结点,返回空。
2.左空右不空:删除该结点,返回右子结点。
3.左不空右空:删除该结点,返回左子结点。
4.左右均不空:找到该结点的右子结点的最左结点,即该结点的直接后继,然后将该结点的值赋给要删除的结点,然后删掉这个后继结点。
左子空,右子从,右子空,左子从,若无子,返作空。
寻右子,左子孙,无左子,方可停,假作真,除真身。
删除后需要在删除结点处开始维护平衡,方法同增加操作时的修正相同,这里不再赘述。

2.3 查找操作

这里我们提供两个查询函数,containsget ,函数实现代码如下。

template <typename K, typename V>
class AVLTree{
public:
	...
	//查找操作
	bool contains(K key);
	V get(K key);
	...
private:
	...
	bool contains(AVLNode<K, V>* node, K key);
	...
};

类外实现如下:

template <typename K, typename V>
bool AVLTree<K, V>::contains(K key){
	return contains(root, key);
}
template <typename K, typename V>
bool AVLTree<K, V>::contains(AVLNode<K, V> *node, K key){
	if (node == NULL){
		return false;
	}
	if (key == node->key){
		return true;
	}
	else if (key < node->key){
		return contains(node->left, key);
	}
	else{
		return contains(node->right, key);
	}
}
template <typename K, typename V>
V AVLTree<K, V>::get(K key){
	AVLNode<K, V> *node = root;
	while (node != NULL){
		if (key == node->key){
			return node->value;
		}
		else if (key < node->key){
			node = node->left;
		}
		else if (key > node->key){
			node = node->right;
		}
	}
	cout << "查询失败!AVL树中不存在" << key << "!" << endl;
	return NULL;
}

2.4 遍历操作

这里与二分搜索树类似,所以只给出中序遍历代码,其余不再赘述。

template <typename K, typename V>
class AVLTree{
public:
	...
	//遍历操作
	void inOrder();
private:
	...
	void inOrder(AVLNode<K, V> *node);
	...
};

类外实现如下:

template <typename K, typename V>
void AVLTree<K, V>::inOrder(){
	cout << "AVL Tree: " << "Size = " << m_size << endl;
	cout << "中序遍历:";
	inOrder(root);
	cout << endl;
}
template <typename K, typename V>
void AVLTree<K, V>::inOrder(AVLNode<K, V> *node){
	if (node == NULL){
		return;
	}
	inOrder(node->left);
	cout << node->key << "  ";
	inOrder(node->right);
}

2.5 其他操作

AVL树还有一些其他的操作,包括 AVL树大小 等的查询操作。

template <typename K, typename V>
class AVLTree{
public:
	...
	int size(){
		return m_size;
	}
	bool isEmpty(){
		return m_size == 0;
	}
	...
};

3. 算法复杂度分析

3.1 增加操作

函数 最坏复杂度 平均复杂度
add O(logn) O(logn)

3.2 删除操作

函数 最坏复杂度 平均复杂度
remove O(logn) O(logn)

3.3 查找操作

函数 最坏复杂度 平均复杂度
contains O(logn) O(logn)
get O(logn) O(logn)

总体情况:

操作 时间复杂度
O(logn)
O(logn)
O(logn)

4. 完整代码

程序完整代码(这里使用了头文件的形式来实现类)如下:

#ifndef __AVLTREE_H__
#define __AVLTREE_H__

template <typename K, typename V>
class AVLNode{
public:
	AVLNode(K key, V value){
		this->key = key;
		this->value = value;
		height = 1;
		left = NULL;
		right = NULL;
	}
public:
	K key;
	V value;
	int height;
	AVLNode<K, V> *left;
	AVLNode<K, V> *right;
};

template <typename K, typename V>
class AVLTree{
public:
	AVLTree(){
		root = NULL;
		m_size = 0;
	}
	int size(){
		return m_size;
	}
	bool isEmpty(){
		return m_size == 0;
	}
	//增加操作
	void add(K key, V value);
	//删除操作
	void remove(K key);
	//查找操作
	bool contains(K key);
	V get(K key);
	//遍历操作
	void inOrder();
private:
	AVLNode<K, V>* add(AVLNode<K, V>* node, K key, V value);
	AVLNode<K, V>* remove(AVLNode<K, V>* node, K key);
	bool contains(AVLNode<K, V>* node, K key);
	int getHeight(AVLNode<K, V>* node);
	int max(int a, int b){ return a > b ? a : b; }
	int getBalanceFactor(AVLNode<K, V>* node);
	AVLNode<K, V>* rightRotate(AVLNode<K, V>* node);
	AVLNode<K, V>* leftRotate(AVLNode<K, V>* node);
	void inOrder(AVLNode<K, V> *node);
private:
	AVLNode<K, V> *root;
	int m_size;
};

template <typename K, typename V>
void AVLTree<K, V>::add(K key, V value){
	root = add(root, key, value);
}
template <typename K, typename V>
AVLNode<K, V>* AVLTree<K, V>::add(AVLNode<K, V>* node, K key, V value){
	if (node == NULL){
		m_size++;
		return new AVLNode<K, V>(key, value);
	}
	else if (key < node->key){
		node->left = add(node->left, key, value);
	}
	else if (key > node->key){
		node->right = add(node->right, key, value);
	}
	else if (key == node->key){
		node->value = value;
		return node;
	}
	//计算平衡因子
	node->height = max(getHeight(node->left), getHeight(node->right)) + 1;
	int balanceFactor = getBalanceFactor(node);
	//平衡维护
	if (balanceFactor > 1 && getBalanceFactor(node->left) >= 0){
		return rightRotate(node);
	}
	else if (balanceFactor < -1 && getBalanceFactor(node->right) <= 0){
		return leftRotate(node);
	}
	else if (balanceFactor > 1 && getBalanceFactor(node->left) < 0){
		node->left = leftRotate(node->left);
		return rightRotate(node);
	}
	else if (balanceFactor < -1 && getBalanceFactor(node->right) > 0){
		node->right = rightRotate(node->right);
		return leftRotate(node);
	}
	return node;
}

template <typename K, typename V>
void AVLTree<K, V>::remove(K key){
	root = remove(root, key);
}
template <typename K, typename V>
AVLNode<K, V>* AVLTree<K, V>::remove(AVLNode<K, V> *node, K key){
	if (node == NULL){
		return node;
	}
	AVLNode<K, V> *resNode = node;
	if (key < node->key){
		node->left = remove(node->left, key);
	}
	else if (key > node->key){
		node->right = remove(node->right, key);
	}
	else if (key == node->key){
		if (node->left == NULL){
			AVLNode<K, V> *rightNode = node->right;
			delete node;
			m_size--;
			resNode = rightNode;
		}
		else if (node->right == NULL){
			AVLNode<K, V> *leftNode = node->left;
			delete node;
			m_size--;
			resNode = leftNode;
		}
		else{
			AVLNode<K, V> *minNode = node->right;
			for (; minNode->left; minNode = minNode->left);
			minNode->right = remove(node->right, minNode->key);
			minNode->left = node->left;
			node->left = node->right = NULL;
			resNode = minNode;
		}
	}
	if (resNode == NULL){
		return NULL;
	}
	//计算平衡因子
	resNode->height = max(getHeight(resNode->left), getHeight(resNode->right)) + 1;
	int balanceFactor = getBalanceFactor(resNode);
	//平衡维护
	if (balanceFactor > 1 && getBalanceFactor(resNode->left) >= 0){
		return rightRotate(resNode);
	}
	else if (balanceFactor < -1 && getBalanceFactor(resNode->right) <= 0){
		return leftRotate(resNode);
	}
	else if (balanceFactor  > 1 && getBalanceFactor(resNode->left) < 0){
		resNode->left = leftRotate(resNode->left);
		return rightRotate(resNode);
	}
	else if (balanceFactor < -1 && getBalanceFactor(resNode->right) > 0){
		resNode->right = rightRotate(resNode->right);
		return leftRotate(resNode);
	}
	return resNode;
}

template <typename K, typename V>
bool AVLTree<K, V>::contains(K key){
	return contains(root, key);
}
template <typename K, typename V>
bool AVLTree<K, V>::contains(AVLNode<K, V> *node, K key){
	if (node == NULL){
		return false;
	}
	if (key == node->key){
		return true;
	}
	else if (key < node->key){
		return contains(node->left, key);
	}
	else{
		return contains(node->right, key);
	}
}
template <typename K, typename V>
V AVLTree<K, V>::get(K key){
	AVLNode<K, V> *node = root;
	while (node != NULL){
		if (key == node->key){
			return node->value;
		}
		else if (key < node->key){
			node = node->left;
		}
		else if (key > node->key){
			node = node->right;
		}
	}
	cout << "查询失败!AVL树中不存在" << key << "!" << endl;
	return NULL;
}

template <typename K, typename V>
int AVLTree<K, V>::getHeight(AVLNode<K, V>* node){
	if (node == NULL){
		return 0;
	}
	return node->height;
}
template <typename K, typename V>
int AVLTree<K, V>::getBalanceFactor(AVLNode<K, V>* node){
	int lHeight = 0, rHeight = 0;
	if (node == NULL){
		return 0;
	}
	if (node->left != NULL){
		lHeight = node->left->height;
	}
	if (node->right != NULL){
		rHeight = node->right->height;
	}
	return lHeight - rHeight;
}
template <typename K, typename V>
AVLNode<K, V>* AVLTree<K, V>::rightRotate(AVLNode<K, V>* node){
	AVLNode<K, V>* res = node->left;
	AVLNode<K, V>* p = res->right;
	res->right = node;
	node->left = p;
	//维护平衡
	node->height = max(getHeight(node->left), getHeight(node->right)) + 1;
	res->height = max(getHeight(res->left), getHeight(res->right)) + 1;
	return res;
}
template <typename K, typename V>
AVLNode<K, V>* AVLTree<K, V>::leftRotate(AVLNode<K, V>* node){
	AVLNode<K, V>* res = node->right;
	AVLNode<K, V>* p = res->left;
	res->left = node;
	node->right = p;
	//维护平衡
	node->height = max(getHeight(node->left), getHeight(node->right)) + 1;
	res->height = max(getHeight(res->left), getHeight(res->right)) + 1;
	return res;
}

template <typename K, typename V>
void AVLTree<K, V>::inOrder(){
	cout << "AVL Tree: " << "Size = " << m_size << endl;
	cout << "中序遍历:";
	inOrder(root);
	cout << endl;
}
template <typename K, typename V>
void AVLTree<K, V>::inOrder(AVLNode<K, V> *node){
	if (node == NULL){
		return;
	}
	inOrder(node->left);
	cout << node->key << "  ";
	inOrder(node->right);
}

#endif

猜你喜欢

转载自blog.csdn.net/qq_35481167/article/details/84502233