C++ 二叉平衡树

二叉平衡树的插入操作 (C++ )

#pragma once

#if 1
using namespace std;
#include<assert.h>
template<class K,class V> // 模板声明;

struct AVLTreeNode {
	AVLTreeNode<K, V>* _left;// 左子树
	AVLTreeNode<K, V>* _right;// 右子树
	AVLTreeNode<K, V>* _parent;// 先驱节点

	int _bf; // balance factor 平衡因子 =  右子树高度 - 左子树高度;

	pair<K, V> _kv; // 二叉平衡树中要装入的树据  pair C++ 特有的数据结构 支持放入俩个类型不同的对象;

	AVLTreeNode(const pair<K, V>& kv)  // AVLTreeNode 的
		: _left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _kv(kv)
		, _bf(0)
	{}
};

template<class K,class V>

class AVLTree {
	typedef AVLTreeNode<K, V> Node;  // 改名 为 Node 

public :
	// 二叉平衡树的插入 
	bool Insert(const pair<K, V>& kv) {
		// 1.先按照二叉搜索树的规则进行插入;
		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 == nullptr,parent 指向 待插入节点的先驱节点;
		// 插入节点 
		cur = new Node(kv);

		if (parent->_kv.first < cur->_kv.first) {
			parent->_right = cur;
			cur->_parent = parent;
		}else {
			parent->_left = cur;
			cur->_parent = parent;
		}

		// 2.向上更新 路劲上的节点的平衡因子
		while (parent != nullptr) { 
			if (parent->_left == cur) {
				parent->_bf--;
			}else {
				parent->_bf++;
			}
			
			if (parent->_bf == 0) {
				// 说明添加子树后 parent 子树没有高度增量,对上层的节点平衡因子没有影响
				break;
			}else if (parent->_bf == 1 || parent->_bf == -1) {
				// 当前parent 子树增加造成parent的高度发生了变化,需要向上继续更新平衡因子
				cur = parent;
				parent = parent->_parent;
			}else if (parent->_bf == 2 || parent->_bf == -2) {
				// parent 所在的子树出现了不平衡,需要根据情况进行相应的旋转处理;
				// (保证这颗子树是二叉搜索树的前提)
				if (parent->_bf == 2) {
					if (cur->_bf == 1) { // 情况一 : parent的右子树的右子树 高度有增量;
						// 操作简称为左单旋 
						RotateL(parent);
					}
					else if (cur->_bf == -1) {// 情况二 : parent的右子树的左子树 高度有增量;
						// 操作简称右左双旋转;
						RotateRL(parent);
					}
				}
				else if (parent->_bf == -2) {
					if (cur->_bf == -1) { // 情况 三 : parent 的左子树的左子树 有高度增量;
						// 操作简称右单旋转
						RotateR(parent);
					}
					else if (cur->_bf == 1) {// 情况 四: parent 的左子树的右子树 有高度增量
						//操作简称 左右双旋
						RotateLR(parent);
					}
				}
			}
			else {
				// 如果走到这一步 说明平衡因子出现问题;
				assert(false); 
			}
		} // 平衡因子处理完成则表明插入元素成功;
		return true;
	}



private :
	Node* _root = nullptr;

	// 左单旋
	void RotateL(Node* parent) { // parent bf == 2 || -2 的节点
		Node* cur = parent->_right;
		Node* curL = cur->_left;
		parent->_right = curL;
		if (curL) {
			curL->_parent = parent;
		}
		cur->_left = parent;
		if (parent->_parent) {// 如果parent 上层有 节点 
			// 讨论 parent 原先是上层节点的左子树还是右子树
			if (parent->_parent->_left == parent) { // 是祖先的左子树
				parent->_parent->_left = cur;
			}
			else { // 是祖先的右子树
				parent->_parent->_right = cur;
			}
			cur->_parent = parent->_parent;
		}
		else {// parent == _root;
			_root = cur;
			cur->_parent = nullptr;
		}
		parent->_parent = cur;
		parent->_bf = 0;
		cur->_bf = 0;
	}


	// 右单旋
	void RotateR(Node* parent) { // 类似与左单旋
		Node* cur = parent->_left;
		Node* curR = cur->_right;

		parent->_left = curR;
		if (parent->_parent) {
			if (parent->_parent->_left == parent) {
				parent->_parent->_left = cur;
			}
			else {
				parent->_parent->_right = cur;
			}
			cur->_parent = parent->_parent;
		}
		else {// parent == _root;
			_root = cur;
			cur->_parent = nullptr;
		}
		cur->_right = parent;
		if (parent->_parent) {
			cur->_parent = parent->_parent;
		}
		parent->_parent = cur;
		parent->_bf = 0;
		cur->_bf = 0;
	}


	// 右左双旋
	void RotateRL(Node* parent) {
		Node* cur = parent->_right;
		Node* curL = cur->_left; 
		int bf = curL->_bf;

		// 先对 cur 子树做右单旋;
		RotateR(cur);
		// 再对 parent 子树做左单旋;  
		RotateL(parent);
		
		// 平衡完后的结果一般是 
		// parent->_right = curL->left;
		// cur->_left = curL->_right;
		// 具体细节要画图 (很简单的)
		// 再根据 curL 平衡前的平衡因子确定 做完旋转之后需要确定这三个节点的平衡因子;
		if (bf == -1) { // 平衡前 curL 的平衡因子是 -1,增量是连接在 curL ->_left 上;
			parent->_bf = 0;
			cur->_bf = 1;
			curL->_bf = 0;
		}
		else if (bf == 1) { // 增量在curL->right 
			curL->_bf = 0;
			cur->_bf = 0;
			parent->_bf = -1;
		}
		else if (bf == 0) {
			curL->_bf = 0;
			cur->_bf = 0;
			parent->_bf = 0;
		}
		else {
			assert(false);
		}
	}


	// 左右双旋 : 类似于 右边左边双旋
	void RotateLR(Node* parent) {
		Node* cur = parent->_left;
		Node* curR = cur->_right;
		int bf = curR->_bf;

		RotateL(cur);
		RotateR(parent);
		
		// 调整完毕后 会出现 
		// cur->_right = curR->_left;
		// parent->_left = curR->_right;
		if (bf == -1) { // 增量在 curR->_right;
			cur->_bf = -1;
			curR->_bf = 0;
			parent->_bf = 0;
		}
		else if (bf == -1) {
			parent->_bf = 1;
			cur->_bf = 0;
			curR->_bf = 0;
		}
		else if(bf == 0){
			parent->_bf = 0;
			cur->_bf = 0;
			curR->_bf = 0;
		}
		else {
			// 平衡因子有问题
			assert(false);
		}
	}
};

#endif
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值