【高阶数据结构】AVL树的旋转与底层(C++实现)

1.AVL树的概念及作用

2.AVL树插入数据的规则

1.按照搜索树的规则插入,然后更新父亲的平衡因子

2.更新父亲的平衡因子后,如果出现一下三种情况需要进行相应处理

3.AVL树的旋转

3.1右单旋

右单旋的所有情况可以抽象为上图:图中,a,b,c均为高度为h(h取0,1,2......)的AVL子树。

插入新结点后,开始旋转:parent->left=subLR; subL->right=parent;

旋转过后依然满足搜索树的规则。

但旋转并没有那么简单,还要调整父子关系,调整根结点,更新平衡因子!

代码:

//右单旋
void RotateR(Node* parent) {
	//旋转,改变树形结构
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
	parent->_left = subLR;
	subL->_right = parent;
	//调整父子关系
	Node* ppNode = parent->_parent;
	if (subLR) subLR->_parent = parent;
	parent->_parent = subL;
	//处理根节点
	if (parent==_root) {
		_root = subL;
		subL->_parent = nullptr;
	}
	else {
		subL->_parent == ppNode;
		if (ppNode->_left == parent) ppNode->_left = subL;
		else ppNode->_right = subL;
	}
	//更新平衡因子
	subL->_bf = parent->_bf = 0;
}

3.2左单旋

思路和代码与右单旋类似。

void RotateL(Node* parent) {
	//旋转,改变树形结构
	Node* subR = parent->_right;
	Node* subRL = subR->_left;
	parent->_right = subRL;
	subR->_left = parent;
	//调整父子关系
	Node* ppNode = parent->_parent;
	if (subRL) subRL->_parent = parent;
	parent->_parent = subR;
	//处理根节点
	if (parent == _root) {
		_root = subR;
		subR->_parent = nullptr;
	}
	else {
		subR->_parent = ppNode;
		if (ppNode->_left == parent) ppNode->_left = subR;
		else ppNode->_right = subR;
	}
	//更新平衡因子
	subR->_bf = parent->_bf = 0;
}

3.3左右双旋

对比一下右单旋的图片,左右双旋的抽象图是把30结点的右子树细致的分为60的结点和60的左右子树。

双旋的情况就是在60这个子树上插入一个新的结点,插入过后需要经过两次旋转。旋转后的结果就是30和90都变成了60的子树。原本为60的子树,变成了30和90的子树。

代码:

//左右双旋
void RotateLR(Node* parent) {
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
	int bf = subLR->_bf;
	RotateL(parent->_left);
	RotateR(parent);
	subLR->_bf = 0;
	if (bf == 0) {
		parent->_bf = 0;
		subL->_bf = 0;
	}
	else if (bf == 1) {
		parent->_bf = 0;
		subL->_bf = -1;
	}
	else if (bf == -1) {
		parent->_bf = 1;
		subL->_bf = 0;
	}
	else assert(false);//理论上不存在这种情况
}

3.4右左双旋

右左双旋与左右双旋正好相反。

代码:

//右左双旋
void RotateRL(Node* parent) {
	Node* subR = parent->_right;
	Node* subRL = subR->_left;
	int bf = subRL->_bf;
	RotateR(parent->_right);
	RotateL(parent);
	subRL->_bf = 0;
	if (bf == 0) {
		parent->_bf = 0;
		subR->_bf = 0;
	}
	else if (bf == 1) {
		parent->_bf = -1;
		subR->_bf = 0;
	}
	else if (bf == -1) {
		parent->_bf = 0;
		subR->_bf = 1;
	}
	else assert(false);//理论上这种情况不存在
}

4.AVL树的底层

模拟实现:

其中:AVLTree_Test1()和AVLTree_Test2()为测试代码。

#pragma once
#include<iostream>
using namespace std;
#include<assert.h>
#include<vector>


//KV模型
namespace key_value {
	template<class k, class v>
	//class BinarySearchTreeNode
	struct AVLTreeNode {
		AVLTreeNode(const pair<k,v>& kv)
			:_kv(kv)
			{}
		AVLTreeNode<k, v>* _left = nullptr;
		AVLTreeNode<k, v>* _right = nullptr;
		AVLTreeNode<k, v>* _parent = nullptr;
		pair<k, v> _kv;
		int _bf = 0;//balance factor
	};


	template<class k, class v>
	class AVLTree {
		typedef AVLTreeNode<k, v> Node;
	public:
		bool insert(const pair<k,v>& kv) {
			if (_root == nullptr) {
				_root = new Node(kv);
				return true;
			}
			Node* parent = nullptr;
			Node* cur = _root;
			while (cur) {
				if (cur->_kv.first < kv.first) {
					parent = cur;
					cur = cur->_right;
				}
				else if (cur->_kv.first > kv.first) {
					parent = cur;
					cur = cur->_left;
				}
				else return false;
			}
			cur = new Node(kv);
			if (parent->_kv.first < kv.first) parent->_right = cur;
			else parent->_left = cur;
			cur->_parent = parent;

			//更新平衡因子
			while (parent) {
				if (cur == parent->_left) parent->_bf--;
				else parent->_bf++;
				if (parent->_bf == 0) break;
				else if (parent->_bf == 1 || parent->_bf == -1) {
					cur = parent;
					parent = parent->_parent;
				}
				else if (parent->_bf == 2 || parent->_bf == -2) {
					//旋转
					if (parent->_bf == -2 && cur->_bf == -1) RotateR(parent);
					else if (parent->_bf == 2 && cur->_bf == 1) RotateL(parent);
					else if (parent->_bf == -2 && cur->_bf == 1) RotateLR(parent);
					else if (parent->_bf == 2 && cur->_bf == -1) RotateRL(parent);
					break;
				}
				else assert(false);
			}
			return true;
		}
		void Inorder() {
			_Inorder(_root);
		}
		Node* Find(const k& key) {
			Node* cur = _root;
			while (cur) {
				if (cur->_kv.first < key) {
					cur = cur->_right;
				}
				else if (cur->_kv.first > key) {
					cur = cur->_left;
				}
				else return cur;
			}
			return nullptr;
		}
		//右单旋
		void RotateR(Node* parent) {
			//旋转,改变树形结构
			Node* subL = parent->_left;
			Node* subLR = subL->_right;
			parent->_left = subLR;
			subL->_right = parent;
			//调整父子关系
			Node* ppNode = parent->_parent;
			if (subLR) subLR->_parent = parent;
			parent->_parent = subL;
			//处理根节点
			if (parent==_root) {
				_root = subL;
				subL->_parent = nullptr;
			}
			else {
				subL->_parent = ppNode;
				if (ppNode->_left == parent) ppNode->_left = subL;
				else ppNode->_right = subL;
			}
			//更新平衡因子
			subL->_bf = parent->_bf = 0;
		}
		void RotateL(Node* parent) {
			//旋转,改变树形结构
			Node* subR = parent->_right;
			Node* subRL = subR->_left;
			parent->_right = subRL;
			subR->_left = parent;
			//调整父子关系
			Node* ppNode = parent->_parent;
			if (subRL) subRL->_parent = parent;
			parent->_parent = subR;
			//处理根节点
			if (parent == _root) {
				_root = subR;
				subR->_parent = nullptr;
			}
			else {
				subR->_parent = ppNode;
				if (ppNode->_left == parent) ppNode->_left = subR;
				else ppNode->_right = subR;
			}
			//更新平衡因子
			subR->_bf = parent->_bf = 0;
		}
		//右左双旋
		void RotateRL(Node* parent) {
			Node* subR = parent->_right;
			Node* subRL = subR->_left;
			int bf = subRL->_bf;
			RotateR(parent->_right);
			RotateL(parent);
			subRL->_bf = 0;
			if (bf == 0) {
				parent->_bf = 0;
				subR->_bf = 0;
			}
			else if (bf == 1) {
				parent->_bf = -1;
				subR->_bf = 0;
			}
			else if (bf == -1) {
				parent->_bf = 0;
				subR->_bf = 1;
			}
			else assert(false);//理论上这种情况不存在
		}
		//左右双旋
		void RotateLR(Node* parent) {
			Node* subL = parent->_left;
			Node* subLR = subL->_right;
			int bf = subLR->_bf;
			RotateL(parent->_left);
			RotateR(parent);
			subLR->_bf = 0;
			if (bf == 0) {
				parent->_bf = 0;
				subL->_bf = 0;
			}
			else if (bf == 1) {
				parent->_bf = 0;
				subL->_bf = -1;
			}
			else if (bf == -1) {
				parent->_bf = 1;
				subL->_bf = 0;
			}
			else assert(false);//理论上不存在这种情况
		}
		bool IsBalance() {
			return _IsBalance(_root);
		}
		int Height() {
			return _Height(_root);
		}
		int Size() {
			return _size(_root);
		}
	private:
		int _size(Node* root) {
			if (root == nullptr) return 0;
			return _size(root->_left) + _size(root->_right) + 1;
		}
		int _Height(Node* root) {
			if (root == nullptr) return 0;
			else
				return max(_Height(root->_left), _Height(root->_right)) + 1;
		}
		bool _IsBalance(Node* root) {
			if (root == nullptr) return true;
			else {
				int leftHeight = _Height(root->_left);
				int rightHeight = _Height(root->_right);
				if (abs(leftHeight - rightHeight) >= 2) {
					cout << root->_kv.first << endl;
					return false;
				}
				//顺便检查一下平衡因子是否有问题
				if ((rightHeight - leftHeight) != root->_bf) {
					cout << root->_kv.first << endl;
					return false;
				}
				return _IsBalance(root->_left) && _IsBalance(root->_right);
			}
		}
		void _Inorder(Node* root) {
			if (root == nullptr) return;
			_Inorder(root->_left);
			cout << root->_kv.first << ":" << root->_kv.second << endl;
			_Inorder(root->_right);
		}
	private:
		Node* _root = nullptr;
	};
}

void AVLTree_Test1() {
	//int arr[] = { 8,3,1,10,6,4,7,14,13 };
	int arr[] = { 4,2,6,1,3,5,15,7,16,14 };
	key_value::AVLTree<int, int> t1;
	for (auto& e : arr) {
		/*if (e == 4) {
			int i = 0;
		}*/
		t1.insert({e,e});
	}
	t1.Inorder();
	cout << t1.IsBalance() << endl;
}

void AVLTree_Test2() {
	const int N = 1000000;
	vector<int> v;
	srand(time(0));
	for (int i = 0; i < N; i++) {
		v.push_back(rand()+i);
	}
	size_t begin1 = clock();
	key_value::AVLTree<int, int> t;
	for (auto e : v) {
		t.insert(make_pair(e, e));
	}
	size_t end1 = clock();

	size_t begin2 = clock();
	for (auto e : v) {
		t.Find(e);
	}
	size_t end2 = clock();
	cout <<"insert"<<"->"<< end1 - begin1 << endl;
	cout << "Balance->"<<t.IsBalance() << endl;
	cout << "Height->" << t.Height() << endl;
	cout << "Size->" << t.Size() << endl;
	cout << "Find->" << end2 - begin2 << endl;
}

测试:

#include"AVLTree.h"
int main() {
	//AVLTree_Test1();
	AVLTree_Test2();
	return 0;
}

从程序运行结果可知:在Release版本下,插入100万个随机数,其中实际插入约63万个数值。

插入耗时:173毫秒(主要是new结点花时间)。

AVL树高度:22。

把63万个随机数全部查找一遍耗时:不到1毫秒。

可见AVL树的查找效率是非常高的!

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

崽崽..

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值