[C++] AVL树的模拟实现

AVL树的定义:一棵树中的所有子树的高度差都不能超过 1

AVLTree.h

#pragma once

template<class K, class V>
struct AVLTreeNode{
	pair<K, V> _kv;
	AVLTreeNode<K, V>* _left;
	AVLTreeNode<K, V>* _right;
	AVLTreeNode<K, V>* _parent;

	int _bf; 	// balance factor平衡因子 = 右树高度 - 左树高度
				//AVL树的判定方法:一棵树中有没有平衡因子超过了 1
				
				//AVL树没有规定一定要使用平衡因子,也可以设定为高度,现场计算

	AVLTreeNode(const pair<K, V>& kv)
		:_kv(kv)
		, _left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _bf(0)	//所有新创建的平衡因子是 0
	{}				//一个数的平衡因子只受其 孩子 的影响,不受其自身影响。
}//而它影响了直系祖先结点
	


template<class K, class V>
class AVLTree{
	typedef AVLTreeNode<K, V> Node;
public:

	//新增在左,父亲平衡因子 -1
	//新增在右,父亲平衡因子 +1
	//持续网祖先更新,祖先bf == 0,则祖先的子树高度不变,停止向上更新
	//祖先|bf| == 1,则祖先所在的子树的高度变化(肯定是由0变化过来的),继续向上更新
	//祖先|bf| == 2,则祖先所在的子树的高度不平衡,开始旋转
	
	bool Insert(const pair<K, V>& kv){
		
		// 1. 插入节点
		if (_root == nullptr){
			_root = new Node(kv);
			_root->_bf = 0;
			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;
			cur->_parent = parent;
		}
		else{
			parent->_left = cur;
			cur->_parent = parent;
		}
		/*如果是搜索树,此时就可以 return true了 */

		// 2. 调平衡
		
		// 2.1.更新平衡因子
		while (parent){
			if (cur == parent->_right){
				parent->_bf++;
			}
			else{
				parent->_bf--;
			}

			if (parent->_bf == 0){ // 高度不变,更新完成
				break;
			}
			else if (abs(parent->_bf) == 1){  // 高度变了,继续完成
				cur = parent;
				parent = parent->_parent;
			}
			else if (abs(parent->_bf) == 2){ // 不平衡,旋转
				if (parent->_bf == 2){
					if (cur->_bf == 1){
						RotateL(parent);
					}
					else if (cur->_bf == -1){
						RotateRL(parent);
					}
				}
				else if (parent->_bf == -2){
					if (cur->_bf == -1){
						RotateR(parent);
					}
					else if (cur->_bf == 1){
						RotateLR(parent);
					}
				}

				break;
			}
			else{
				assert(false);	//不允许逻辑执行到此,到达说明插入之前就已经不平衡了
			}
		}
		return true;
	}

	//左单旋
	void RotateL(Node* parent){
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;

		subR->_left = parent;
		Node* ppNode = parent->_parent;
		parent->_parent = subR;

		if (parent == _root){
			_root = subR;
			_root->_parent = nullptr;
		}
		else{
			if (ppNode->_left == parent)
				ppNode->_left = subR;
			else
				ppNode->_right = subR;

			subR->_parent = ppNode;
		}

		parent->_bf = subR->_bf = 0;
	}

	//右单旋
	void RotateR(Node* parent){
		Node* subL = parent->_left;		//左孩子
		Node* subLR = subL->_right;		//左孩子的右孩子

		parent->_left = subLR;
		if (subLR)
			subLR->_parent = parent;

		subL->_right = parent;

		Node* ppNode = parent->_parent;		//parent结点还有祖先结点
		parent->_parent = subL;

		if (ppNode == nullptr){		//parent就是原树的根
			_root = subL;
			_root->_parent = nullptr;
		}
		else{
			if (ppNode->_left == parent){
				ppNode->_left = subL;
			}
			else{
				ppNode->_right = subL;
			}

			subL->_parent = ppNode;
		}
		parent->_bf = subL->_bf = 0;
	}

	//先左后右双旋
	void RotateLR(Node* parent){
		RotateL(parent->_left);
		RotateR(parent);
	}

	//先右后左双旋
	void RotateRL(Node* parent){
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		int bf = subRL->_bf;	//保存subRL的平衡因子,因为在下面两行会置 0

		RotateR(parent->_right);
		RotateL(parent);

		if (bf == 0){
			parent->_bf = subRL->_bf = subR->_bf = 0;
		}
		else if (bf == 1){		//在c插入的新结点
			subR->_bf = 0;
			parent->_bf = -1;
			subRL->_bf = 0;
		}
		else if (bf == -1){		//在b插入的新结点
			parent->_bf = 0;
			subR->_bf = 1;
			subRL->_bf = 0;
		}
	}

	void InOrder(){
		_InOrder(_root);
		cout << endl;
	}

	void _InOrder(Node* root){
		if (root == nullptr)
			return;

		_InOrder(root->_left);
		cout << root->_kv.first << " ";
		_InOrder(root->_right);
	}

	int _Height(Node* root){
		if (root == nullptr){
			return 0;
		}

		int leftheight = _Height(root->_left);
		int rightheight = _Height(root->_right);

		return leftheight > rightheight ? leftheight + 1 : rightheight + 1;
	}

	bool IsBalance(){		//this指针是隐含的,所以需要封装
		return _IsBalance(_root);
	}

	bool _IsBalance(Node* root){
		if (root == nullptr)
			return true;

		int leftheight = _Height(root->_left);
		int rightheight = _Height(root->_right);
		if (rightheight-leftheight != root->_bf){
			cout << root->_kv.first << "平衡因子异常" << endl;
			return false;
		}

		return abs(leftheight - rightheight) < 2
			&& _IsBalance(root->_left)
			&& _IsBalance(root->_right);
	}

private:
	Node* _root = nullptr;
};

测试代码

void TestAVLTree(){
	AVLTree<int, int> t;
	//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };	//说明是搜索树
	int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
	for (auto e : a){
		t.Insert(make_pair(e, e));
	}

	t.InOrder();
	cout << t.IsBalance() << endl;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

giturtle

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

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

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

打赏作者

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

抵扣说明:

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

余额充值