c++ AVLTree(高度平衡的搜索二叉树)

#pragma once

#include <iostream>

using namespace std;

#define	NEG  -1
#define	ZERO  0
#define	POS 1

template <class K,class V>

struct AVLTreeNode//树的节点
{
	K _key;
	V _value;
	AVLTreeNode* _left;
	AVLTreeNode* _right;
	AVLTreeNode* _parent;
	int _bf;

	AVLTreeNode(const K& key,const V& value)
		:_key(key)
		, _value(value)
		, _left(NULL)
		, _right(NULL)
		, _parent(NULL)
		, _bf(0)//平衡因子 取值 -1 0 1 (左高1  相等 右高1)
	{}

};

template<class K,class V>

class AVLTree
{
	typedef AVLTreeNode<K, V> Node;
public:
	AVLTree()
		:_root(NULL)
	{}
	~AVLTree(){}

	bool Insert(const K& key,const V& value)//插入
	{
		if (_root == NULL)
		{
			_root = new Node(key,value);//空树 直接插入
			return true;
		}
		Node* cur = _root, *prev = NULL;//当前 与 之前 节点指针
		while (cur){
			if (cur->_key < key)//插入key 比当前节点 key大 跳到右
			{
				if (cur->_right){//右不为空继续
					prev = cur;
					cur = cur->_right;
					if (cur->_bf == ZERO)//如果节点的bf为0,说明插入(如果成功),会改变prev->bf的值
						prev->_bf++;
				}
				else
				{//如果右为空 到达插入节点位置,插入cur->bf ++
					cur->_right = new Node(key,value);
					cur->_right->_parent = cur;
					cur->_bf++;
					break;
				}
			}
			else if (cur->_key>key)//同理 向左 插入
			{
				if (cur->_left){
					prev = cur;
					cur = cur->_left;
					if (cur->_bf == ZERO)
						prev->_bf--;
				}
				else
				{
					cur->_left = new Node(key, value);
					cur->_left->_parent = cur;

					cur->_bf--;
					break;
				}
			}
			else//key相等,插入失败,依次将改变的平衡因子 改回来
			{
				while (prev&&cur->_bf == ZERO)
				{
					if (prev->_left == cur)
						prev->_bf++;
					else
						prev->_bf--;
					cur = prev;
					prev = prev->_parent;
				}
				return false;

			}
		}
		//插入结束 对整棵树进行调节 使其继续平衡
		//高度不变
		if (cur->_bf == ZERO)
			return true;
		else//高度改变
		{
			//找高度变为-2 或 2的节点旋转
			while (prev)
			{
				if (prev->_bf < -1)//左高2
				{
					if (cur->_bf <= -1)//右旋
					{
						_RotateR(prev);
						cout << "右旋"<<endl;
						break;
					}
					else//左右旋
					{
						_RotateL(cur);
						_RotateR(prev);
						cout << "左右旋" << endl;

						break;
					}
				}
				else if (prev->_bf > 1)//右高2
				{
					if (cur->_bf >= 1)//左旋
					{
						_RotateL(prev);
						cout << "左旋" << endl;

						break;
					}
					else//右左旋
					{
						_RotateR(cur);
						_RotateL(prev);
						cout << "右左旋" << endl;
						break;
					}
				}
				cur = prev;
				prev = prev->_parent;
			}
		}
		return true;

	}

	bool IsBalance()
	{
		if (_root == NULL)
			return true;
		return _Isbalance(_root);
	}

	Node* Find(const K& key)
	{
		Node * cur = _root;
		while (cur){
			if (cur->_key > key)
				cur = cur->_left;
			else if (cur->_key < key)
				cur = cur->_right;
			else
				return cur;

		}
		return NULL;
	}

	bool Remove(const K& key)
	{
		if (_root == NULL)
		{
			return false;//空树删除失败
		}
		Node* cur = _root, *prev = NULL;
		while (cur){
			if (cur->_key < key)//删除位置在cur 右
			{
				if (cur->_right){//右非空,继续找
					prev = cur;
					cur = cur->_right;
				}
				else//右空,未找到删除节点 返回
					return false;
			}
			else if (cur->_key>key)//删除位置在左
			{
				if (cur->_left){
					prev = cur;
					cur = cur->_left;
				}
				else
					return false;
			}
			else
			{
				Node* parent = cur->_parent;//记录删除节点的 父
				if (cur->_left == NULL)//删除节点 左空,直接使其右与prev相连
				{

					if (prev == NULL){//prev为空,删除根节点,根节点改变
						_root = cur->_right;
						delete cur;

						return true;
					}
					if (prev->_right == cur){//prev右为cur,cur的右连到prev右
						prev->_bf--;//平衡因子 减少
						prev->_right = cur->_right;
						if (cur->_right)
							cur->_right->_parent = prev;
					}
					if (prev->_left == cur){//prev左为 cur
						prev->_left = cur->_right;
						prev->_bf++;
						if (cur->_right)
							cur->_right->_parent = prev;
					}
					delete cur;//释放节点
					cur = prev;//将cur prev指向有效节点
					prev = cur->_parent;

				}
				else if (cur->_right == NULL)//同上 cur右为空
				{
					if (prev == NULL){
						_root = cur->_left;
						delete cur;

						return true;
					}
					if (prev->_right == cur){
						prev->_bf--;
						prev->_right = cur->_left;
						if (cur->_left)
							cur->_left->_parent = prev;
					}
					if (prev->_left == cur){
						prev->_left = cur->_left;
						prev->_bf++;
						if (cur->_left)
							cur->_left->_parent = prev;
					}
					delete cur;
					cur = prev;
					prev = cur->_parent;

				}
				else
				{//cur左右都非空,为了避免换当前root的复杂操作,替换为删除cur左孩子 最右 节点 ,或者cur右孩子的 最左 节点,将其内容拷贝给cur
					Node* tmp = cur;
					prev = cur;
					cur = cur->_right;

					while (cur->_left)//找右树最左
					{
						prev = cur;
						cur = cur->_left;
					}
					tmp->_key = cur->_key;
					tmp->_value = cur->_value;//拷贝值

					if (cur == prev->_left)//调节prev bf并将 cur右树连接到prev                              
						prev->_bf++;
						prev->_left = cur->_right;

					}
					if (cur == prev->_right)//同上
					{
						prev->_bf--;
						prev->_right = cur->_right;

					}
					tmp = cur;//记录删除位置
					cur = prev;
					parent = cur;//cur prev 指向有效节点
					prev = cur->_parent;

					delete tmp;//删除tmp

				}
				while (prev &&cur->_bf == ZERO)//删除节点 父树高度可能改变,依次确认并修改 bf (cur bf为0 说明是 -1 或 1 变来 高度发生改变  需修改父节点 bf)
				{
					if (cur == prev->_left){
						prev->_bf++;
					}
					if (cur == prev->_right)
					{
						prev->_bf--;
					}

					cur = prev;
					prev = prev->_parent;
				}

				prev = parent;//prev指向 实际删除节点的父节点
				if (prev->_bf < ZERO)
					cur = prev->_left;
				if (prev->_bf > ZERO)
					cur = prev->_right;
				if (prev->_bf == ZERO){
					cur = prev;
					prev = prev->_parent;
				}
				break;
			}
		}

			//找高度变为-2 或 2的节点旋转
		while (prev)
		{
			if (prev->_bf < -1)//左高2
			{
				cur = prev->_left;//因为删除一侧节点可能需要另一侧旋转,因此需要对 cur重新赋值
				if (cur && (cur->_bf <= -1 || cur->_bf == ZERO))//右旋
				{
					_RotateR(prev);
					if (prev->_left&&prev->_right == NULL)//判断旋转后 prev的bf
						prev->_bf--;
					cout << "右旋" << endl;

				}
				else//左右旋
				{
					_RotateL(cur);
					_RotateR(prev);
					cout << "左右旋" << endl;
				}
				cur = prev->_parent;
				prev = cur->_parent;
				while (prev&&cur->_bf == ZERO)//依次修改旋转完毕的prev的bf
				{
					if (cur == prev->_left)
						prev->_bf++;
					else
						prev->_bf--;
					cur = prev;
					prev = prev->_parent;
				}
			}
			else if (prev->_bf > 1)//右高2
			{
				cur = prev->_right;
				if (cur && (cur->_bf >= 1 || cur->_bf == ZERO))//左旋
				{
					_RotateL(prev);
					cout << "左旋" << endl;
					if (prev->_right&&prev->_left == NULL)
						prev->_bf++;
				}
				else//右左旋
				{
					_RotateR(cur);
					_RotateL(prev);
					cout << "右左旋" << endl;
				}
				cur = prev->_parent;
				prev = cur->_parent;
				while (prev&&cur->_bf == ZERO)
				{
					if (cur == prev->_left)
						prev->_bf++;
					else
						prev->_bf--;
					cur = prev;
					prev = prev->_parent;
				}
			}
			cur = prev;
			if (prev)
				prev = prev->_parent;
		}
		return true;
	}

private:
	Node* _root;

	int _height(Node* root)
	{
		if (root == NULL)
			return 0;
		int left = 1, right =1;
		left += _height(root->_left);
		right += _height(root->_right);
		return left > right ? left : right;
	}

	bool _Isbalance(Node* root)//判断 数是否平衡 bf是否匹配
	{
		if (root == NULL)
			return true;
		/*if (root ->_left==NULL&&root->_right==NULL)
			return true;*/
		bool left = _Isbalance(root->_left);
		bool right = _Isbalance(root->_right);

		int num1 = 1;
		num1+=_height(root->_left);
		int num2 = 1;
		num2+=_height(root->_right);
		if (left == false || right == false)
		{
			cout << "not balace!" << " key: " << root->_key << "bf: " << root->_bf << endl;
			return false;
		}
		if (num2-num1!=root->_bf)
		{
			cout << "bf error!" << "key:" << root->_key << "bf: " << root->_bf << "a-b:" << num1-num2 << endl;
			return false;
		}

		if (abs(num1-num2) <= 1)
			return true;
		return false;

	}
	//旋转后 bf 调节总结:左旋 bf 减小 右旋 bf 增加;sub=2 ,parent变化 3,sub变化 2;sub=1,parent 变化2,sub变化 1;
	void _RotateR(Node* parent)//右旋
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		Node* ppNode=parent->_parent;

		subL->_right = parent;
		parent->_parent = subL;
		parent->_left = subLR;
		if (subLR)
			subLR->_parent = parent;
		if (ppNode)
		{
			if (ppNode->_left == parent)
				ppNode->_left = subL;
			else
				ppNode->_right = subL;

		}
		else
			_root = subL;
		subL->_parent = ppNode;//旋转
		//修改 bf
		if (subL->_bf == -2){
			parent->_bf = 1;
			subL->_bf=0;
		}
		else
		{
			subL->_bf++;
			parent->_bf = 0;
		}

	}

	void _RotateL(Node* parent)//左旋
	{
		Node* subR= parent->_right;
		Node* subRL = subR->_left;
		Node* ppNode = parent->_parent;

		subR->_left = parent;
		parent->_parent = subR;
		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;
		if (ppNode)
		{
			if (ppNode->_left == parent)
				ppNode->_left = subR;
			else
				ppNode->_right = subR;

		}
		else
			_root = subR;
		subR->_parent = ppNode;//以上为左旋转

		//以下下修改 bf 值
		if (subR->_bf == 2)//右孩子的高度为2 说明旋转前 高度差在右孩子的下方,旋转后parent 右支 没有可以连接的,高度会降3 从2变为-1
		{
			parent->_bf = -1;
			subR->_bf = 0;
		}
		else{ //右孩子高度为1,旋转后高度将2 buf为 0,而右孩子  高度将1;
			parent->_bf = 0;
			subR->_bf--;
		}
	}
};
时间: 2024-10-11 11:22:51

c++ AVLTree(高度平衡的搜索二叉树)的相关文章

高度平衡的二叉搜索树—AVLTree

AVL树 AVL树又称为高度平衡的二叉搜索树,是1962年有俄罗斯的数学家G.M.Adel'son-Vel'skii和E.M.Landis提出来的.它能保持二叉树的高度平衡,尽量降低二叉树的高度,减少树的平均搜索长度. AVL树的性质 左子树和右子树的高度之差的绝对值不超过1 树中的每个左子树和右子树都是AVL树 每个节点都有一个平衡因子(balance factor--bf),任一节点的平衡因子是-1,0,1.(每个节点的平衡因子等于右子树的高度减去左子树的高度 ) AVL树的效率 一棵AVL

判断一个数列是不是搜索二叉树后续遍历输出的结果

剑平面阿里被问到这个,刚开始画了下看有什么性质,乱蒙了几个都被推翻了,初始感觉就是要O(n)的,因为印象中BST的构树都可以O(nlogn)搞定.然后剑平说最后一个数肯定是根节点,一下反应过来了,就是二分出间隔点然后两边递归判断,不过这好像还是构树的思路,可以把整棵树构造出来.然后剑平说不是二分,直接遍历.不科学啊,明显的二分,然后去网上搜一下,都是遍历的,O(n^2)的吧.想了想,二分是当做合法的情况来构树的,不合法怎么判断?构造出搜索二叉树后中序遍历一下不就行了么,妥妥的O(nlogn)吧.

搜索二叉树

二叉查找树(BinarySearch Tree,也叫二叉搜索树,或称二叉排序树Binary Sort Tree)或者是一棵空树,或具有如下性质: 每个节点都有一个作为搜索依据的关键码(key),所有节点的关键码互不相同. 左子树上所有节点的关键码(key)都小于根节点的关键码(key). 右子树上所有节点的关键码(key)都大于根节点的关键码(key). 左右子树都是二叉搜索树. 二叉搜索树相关操作: (1)插入:新节点 在二叉查找树中插入新结点,要保证插入新结点后仍能满足二叉查找树的性质.插入

java递归方法建立搜索二叉树,具备查找关键字,插入新节点功能

二叉排序树的定义: 二叉排序树满足以下三个性质(BST性质): <1>若它的左子树非空,则左子树上所有节点的值均小于根节点的值 <2>若它的右子树非空,则右子树上所有节点的值均大于根节点的值 <3>左,右子树本身又各是一棵二叉排序树 根据二叉排序树的BST性质,可以说二叉排序树每个节点上的值(或称关键字)都是唯一的,并且二叉排序树以中序遍历输出的结果必然是一个有序的递增序列. 如下图所示: 用递归方法建立二叉排序树,减少了繁复的比较程序,效率较高.只需要知道每个节点的值

数据结构--‘搜索二叉树’

'二叉树'是数据结构中比较重要的一部分,这里主要讨论一下'搜索二叉树',针对'搜索二叉树的插入.删除和查找节点进行分情况讨论,希望能够帮助读者更加的理解搜索二叉树的原理. ◆搜索二叉树的性质: 1.每个节点都有一个一个作为搜索依据的关键码,所有节点的关键码都不相同. 2.左子树所有的关键码(key)都小于根节点的关键码(key). 3.右子树所有的关键码(key)都大于根节点的关键码(key). 4.左.右子树都是二叉搜索树. 实现'搜索二叉树'的节点结构可以实现为K形式,和K.V形式,若实现K

【数据结构】搜索二叉树的(递归与非递归)实现,包括:增Insert,删Remove,查Find

搜索二叉树,是二叉树一种特殊的结构. 特点: (1)每个节点都有一个关键码,并且关键码不重复. (2)左子树上的每个节点的关键码都小于根节点的关键码. (3)右子树上的每个节点的关键码都大于根节点的关键码. (4)左右子树都是搜索二叉树. 下面,为方便大家理解,我举例画一个搜索二叉树,如下: 代码见下: #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; //搜索二叉树的节点结构 template&

通过控制高度来控制搜索条件

需求:通过更多按钮来实现搜索条件的收缩和展开. 以前没做过类似的需求,自己去京东等各大网站参考了一下,大概明白了思路: 通过控制搜索块的高度来隐藏搜索条件 $("span.o-more").bind("click", function () { var $cur = $(this).parent().prev(); if ($cur.hasClass("unfold")) { $cur.removeClass("unfold"

《github一天一道算法题》:搜索二叉树接口实现大合集

读书.思考.写代码! 说明: (1)这里实现了搜索二叉树的全部常用操作 (2)限于时间和精力,实现的较为粗糙,内存泄露.成员变量访问控制.返回类型.异常安全等没有照顾的到 (3)一切实现的手段都是贴近底层操作,关注原理.以后可能对推倒重来,实现一个完备的接口系统. /********************************************* * [email protected] * 题目:二叉树接口实现大合集 * 具体:二叉树的创建.插入.最大值.最小值.前中后序递归遍历与非递

搜索二叉树的操作

搜索二叉树的数据结构定义: /*二叉搜索树的结构定义*/ typedef struct TreeNode* SearchTree; typedef struct TreeNode* Position; struct TreeNode { int Element; SearchTree Left; SearchTree Right; } 搜索二叉树的插入操作: SearchTree Insert(int x, SearchTree T) { if(T == NULL)//空树 { T = mall