首页 > 编程语言 >C++:AVL树-模拟实现完整代码

C++:AVL树-模拟实现完整代码

时间:2024-11-21 20:16:37浏览次数:3  
标签:Node bf cur parent C++ AVL root 模拟 left

在这里插入图片描述

文章目录


AVL树-模拟实现完整代码总结:

#pragma once

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

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;         // 平衡因子

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

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* cur = _root;
		Node* parent = nullptr;

		while (cur)
		{
			// 小于往左走
			if (kv.first < cur->_kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (kv.first > cur->_kv.first)   // 大于往右走
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return false;
			}
		}

		cur = new Node(kv);
		// 链接
		if (cur->_kv.first < parent->_kv.first)
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		cur->_parent = parent;

		// 通过平衡因子控制平衡

		while (parent)      // 如果parent为空,就停止
		{
			if (cur == parent->_left)
			{
				parent->_bf--;     // 如果新加入的结点在左侧,父亲平衡因子减1
			}
			else
			{
				parent->_bf++;    // 如果新加入的结点在右侧,父亲平衡因子加1
			}

			if (parent->_bf == 0)
			{
				break;      // 父亲平衡因子为0,更新结束
			}
			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)
				{
					RotateL(parent);
				}
				// 右单旋
				else if (parent->_bf == -2 && cur->_bf == -1)
				{
					RotateR(parent);
				}
				// 右左双旋
				else if (parent->_bf == 2 && cur->_bf == -1)
				{
					RotateRL(parent);
				}
				// 左右双旋
				else if (parent->_bf == -2 && cur->_bf == 1)
				{
					RotateLR(parent);
				}
				break;
			}
		}

		return true;
	}

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

		// 重新链接
		parent->_right = curleft;
		if (curleft) // 如果curleft存在
		{
			curleft->_parent = parent;
		}

		cur->_left = parent;

		Node* ppnode = parent->_parent;
		parent->_parent = cur;

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

			cur->_parent = ppnode;
		}

		// 更改平衡因子
		parent->_bf = cur->_bf = 0;
	}

	// 右单旋
	void RotateR(Node* parent)
	{
		Node* cur = parent->_left;
		Node* curright = cur->_right;

		parent->_left = curright;

		if (curright)
		{
			curright->_parent = parent;
		}

		cur->_right = parent;

		Node* ppnode = parent->_parent;
		parent->_parent = cur;
		if (ppnode == nullptr)
		{
			cur->_parent = nullptr;
			_root = cur;
		}
		else
		{
			if (ppnode->_left == parent)
			{
				ppnode->_left = cur;
			}
			else
			{
				ppnode->_right = cur;
			}
			cur->_parent = ppnode;
		}

		// 改变平衡因子
		parent->_bf = cur->_bf = 0;
	}

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

		// 右旋
		RotateR(cur);
		// 左旋
		RotateL(parent);

		// 调整平衡因子
		if (bf == 0)
		{
			parent->_bf = 0;
			cur->_bf = 0;
			curleft->_bf = 0;
		}
		else if (bf == 1)
		{
			parent->_bf = -1;
			cur->_bf = 0;
			curleft->_bf = 0;
		}
		else if (bf == -1)
		{
			parent->_bf = 0;
			cur->_bf = 1;
			curleft->_bf = 0;
		}
		else
		{
			assert(false);
		}
	}

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

		RotateL(cur);
		RotateR(parent);

		// 调整平衡因子
		if (bf == 0)
		{
			parent->_bf = 0;
			cur->_bf = 0;
			curright->_bf = 0;
		}
		else if (bf == 1)
		{
			parent->_bf = 0;
			cur->_bf = -1;
			curright->_bf = 0;
		}
		else if (bf == -1)
		{
			parent->_bf = 1;
			cur->_bf = 0;
			curright->_bf = 0;
		}
		else
		{
			assert(false);
		}
	}

	int Height()
	{
		return Height(_root);
	}

	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()
	{
		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 << "->" << root->_bf << endl;
		}

		return abs(rightHeight - leftHeight) < 2
			&& IsBalance(root->_left)
			&& IsBalance(root->_right);
	}

private:
	Node* _root = nullptr;
};

查找错误的方式

AVL树这里的错误很难被调试找出来,数据量一多,找错误头都大了,为了更快的定位错误,J桑在这里提供一种方法

标签:Node,bf,cur,parent,C++,AVL,root,模拟,left
From: https://blog.csdn.net/Jdxxwu/article/details/143927896

相关文章

  • C++:探索AVL树旋转的奥秘
    文章目录前言AVL树为什么要旋转?一、插入一个值的大概过程1.插入一个值的大致过程2.平衡因子更新原则3.旋转处理的目的二、左单旋1.左单旋旋转方式总处理图2.左单旋具体会遇到的情况3.左单旋代码总结三、右单旋1.右单旋旋转方式总处理图2.右单旋具体会遇到的......
  • C/C++中的const
    1.在C语言中 在C语言中,const 是一个关键字,用于修饰变量。它的主要作用是定义常量,即被 const 修饰的变量的值不能被修改。例如: constinta=10;//这里定义了一个整型常量 a ,尝试给 a 重新赋值(如 a=20; )会导致编译错误。const 也可以用于修饰指针。如果......
  • C++中的移动语义
    一、移动语义1.定义:在C++中,移动语义是一种优化技术。移动语义允许资源的“移动”而不是“拷贝”。在传统的C++中,当一个对象被赋值或传递给函数时,通常会发生拷贝操作,这会导致性能下降,尤其是在处理大型对象时。移动语义通过引入右值引用和移动构造函数、移动赋值运算符,允许......
  • 【C++学习笔记】一个先学了Java,Python,Csharp最后再来学C++的菜狗笔记
    1.字符串1.char数组charstr[]="helloworld";可以使用cstring库中的函数(如strlen,strcpy)。2.string类型#include<string>stringstr="helloworld";与csharp,java等语言不同的是动态分配内存,由标准库管理。支持操作符重载(如+,==等)。std::string是可变的,类似......
  • NOIP 模拟 18
    NOIP模拟18最近老是犯唐,这次也是。T1图容易得到暴力代码:namespaces1{ boolsta[MAXN*MAXN]; boolS[MAXN],T[MAXN]; strings; intans; intmain(){cin>>n>>m; for(inti=1;i<=m;++i){ cin>>s; memset(S,0,sizeof(bool)*(n+5)); memset(T,......
  • C++系统教程007-数据类型06(cin输入语句)
    练习:1.控制输出精确度本实例中,定义一个整型变量并赋值,定义一个双精度变量并赋值,利用cout输出这两个不同精度的格式。//控制精度#include<iostream>usingnamespacestd;intmain(){ intx=123; doubley=3.1415; cout<<"x="; cout.width(10);//设置输出域宽为10 ......
  • [题解](更新中)2024/11/21 模拟赛 / 2023牛客OI赛前集训营-提高组(第二场) A~B
    整套都是原题所以就不设密码了(原题页面:https://ac.nowcoder.com/acm/contest/65193题解:https://www.nowcoder.com/discuss/540225827162583040\(60+30+20+20=130\)。每日挂分之T2线段树不开\(4\)倍+\(10^6\)数量级输入不关同步流,\(\bf\colorbox{MidnightBlue}{\texttt{\color{......
  • C++11-chrono时间库解析
    目录一、具体作用用途二、C++std::chrono时间库概述2.1、std::chrono命名空间的作用和用途2.2、基本组成部分:duration、time_point和clock三、duration的使用详解3.1、duration表示时间段的概念和使用方法3.2、duration的各种单位和精度选项3.3、使用示例四、time_p......
  • 【C++】类和对象-深度剖析默认成员函数-下
     >......
  • C++指针函数体内部初始化需要注意的地方
    有如下代码:voidchangePtr(int*p){*p=4;}intmain(){int*p=newint(5); changePtr(p);cout<<"*p:"<<*p<<endl;}以上代码我们都知道传递指针,函数改变了指针指向地址内的数据,函数体外部调用时p指向地址发生了改变,输出结果由5->4。但是在......