平衡二叉树详解(附带完整代码)

平衡二叉树:

高度的概念:距离根节点有多少层

左右子树的高度差不超过1的有序二叉树。

平衡的概念:结点的平衡因子 = 结点的左子树深度 — 结点的右子树深度。

若平衡因子的取值为-1、0或1时,该节点是平衡的,否则是不平衡的。

旋转:

由于平衡因子不平衡,所以引入了旋转的概念,来使得二叉树平衡

最简单的四种旋转情况

LL旋转

由于10的左孩子的高度为2,右孩子高度为0,平衡因子为2,二叉树不平衡,需要进行旋转操作,如何旋转?

将10节点进行左旋操作,类似于将10节点顺时针旋转
在这里插入图片描述

RR旋转

由于10的右孩子的高度为2,左孩子高度为0,平衡因子为 -2,二叉树不平衡,需要进行旋转操作

将10节点进行右旋操作,类似于将10节点逆时针旋转

在这里插入图片描述

LR旋转

先将9节点进行左旋操作,让8节点成为9的左孩子;再进行一次右旋操作,9成为根节点
在这里插入图片描述

RL旋转

先将9节点进行右旋操作,10节点成为9的右孩子;再进行一次左旋操作,9成为根节点
在这里插入图片描述


较复杂的四种旋转情况

LL旋转

当添加的新节点成为最小不平衡树的左孩子的左子树时产生:

规划可知8节点应为根节点;

旋转过程:

  1. 根节点12右旋转(顺时针)成为8节点的右孩子。
  2. 8节点的右孩子成为12的左孩子。
  3. 8节点成为新的根节点。
    在这里插入图片描述

RR旋转

当添加的新节点成为最小不平衡树的右孩子的右子树时产生:

规划可知8应为新的根节点:

旋转过程:

  1. 根节点6左旋转(逆时针),成为8的左孩子。
  2. 8的左孩子成为6节点的右孩子。
  3. 8成为新的根节点。
    在这里插入图片描述

LR旋转

当添加的新节点成为最小不平衡树的左孩子的右子树时产生:

规划可知,7应该成为新的根节点

旋转过程:

  1. 7节点左旋成为10的相邻左孩子。
  2. 6节点成为7节点的左孩子。
  3. 根节点右旋成为7节点的相邻右孩子。
  4. 7节点的右孩子成为10节点的左孩子。
  5. 7节点成为新的根节点
    在这里插入图片描述

RL旋转

当添加的新元素成为最小不平衡树的右孩子的左子树时产生:

7应该成为根节点

旋转过程:

  1. 7节点右旋成为根节点的相邻右孩子。
  2. 8节点成为7节点的右孩子。
  3. 根节点左旋成为7的相邻左孩子。
  4. 7节点的左孩子成为4节点的右孩子。
  5. 7成为新的根节点。
    在这里插入图片描述

完整代码

#pragma once

#include <iostream>
using namespace std;

template <class T>
struct TreeNode
{
	T data;
	TreeNode* pLeft;		//左孩子
	TreeNode* pRight;		//右孩子
	int height;				//高度
	TreeNode(const T& data)
	{
		this->data = data;
		pLeft = pRight = nullptr;
		height = 0;
	}
};

template <class T>
class ACL_Tree
{
public:
	ACL_Tree() { pRoot = nullptr; }
	~ACL_Tree() {}
	//插入节点
	void Insert_Node(const T& newdata)
	{
		_insert(pRoot, newdata);
	}
	//获取某个节点的高度
	int _getHeight(TreeNode<T>* root);

	//情况一 右旋
	TreeNode<T>* RR(TreeNode<T>* root);
	//情况二 左旋
	TreeNode<T>* LL(TreeNode<T>* root);
	//情况三 左右旋
	TreeNode<T>* LR(TreeNode<T>* root);
	//情况四 右左旋
	TreeNode<T>* RL(TreeNode<T>* root);
private:
	void _insert(TreeNode<T>*& pRoot, const T& data);
private:
	TreeNode<T>* pRoot;
};


template <class T>
void ACL_Tree<T>::_insert(TreeNode<T>*& pRoot, const T& data)
{
	if (pRoot == nullptr)
	{
		//如果当前节点为空,则直接插入
		pRoot = new TreeNode<T>(data);
	}
	else if (data < pRoot->data)
	{
		//左插
		_insert(pRoot->pLeft, data);
		//判断是否需要旋转
		if (_getHeight(pRoot->pLeft) - _getHeight(pRoot->pRight) > 1)
		{
			if (data < pRoot->pLeft->data)
			{
				//RR  左旋
				pRoot = RR(pRoot);
			}
			else
			{
				//LR  左右旋
				pRoot = LR(pRoot);
			}
		}
	}
	else
	{
		//右插
		_insert(pRoot->pRight, data);
		if (_getHeight(pRoot->pRight) - _getHeight(pRoot->pLeft) > 1)
		{
			if (data >= pRoot->pRight->data)
			{
				//LL 右旋
				pRoot = LL(pRoot);
			}
			else
			{
				//RL  右左旋
				pRoot = RL(pRoot);
			}
		}
	}
	//3 设置高度
	int leftHeight = _getHeight(pRoot->pLeft);
	int rightHeight = _getHeight(pRoot->pRight);

	pRoot->height = 1 + (
		(leftHeight > rightHeight) ? leftHeight : rightHeight
		);
}

template<class T>
//获取某个节点的高度
inline int ACL_Tree<T>::_getHeight(TreeNode<T>* root)
{
	if (root)
	{
		return root->height;
	}
	return 0;
}
//右旋
template<class T>
inline TreeNode<T>* ACL_Tree<T>::RR(TreeNode<T>* pRoot)
{
	//1. pTemp临时存储pRoot的pLeft
	TreeNode<T>* pTemp = pRoot->pLeft;
	//2. pTemp的右孩子成为pRoot的左孩子
	pRoot->pLeft = pTemp->pRight;
	//3. pRoot成为pTemp的右孩子
	pTemp->pRight = pRoot;
	//4. 高度设置
	pRoot->height = 1 + ((_getHeight(pRoot->pLeft) > _getHeight(pRoot->pRight)) ?
		_getHeight(pRoot->pLeft) : _getHeight(pRoot->pRight));
	pTemp->height=1+ ((_getHeight(pTemp->pLeft) > _getHeight(pTemp->pRight)) ?
		_getHeight(pTemp->pLeft) : _getHeight(pTemp->pRight));

	return pTemp;
}
//左旋
template<class T>
inline TreeNode<T>* ACL_Tree<T>::LL(TreeNode<T>* pRoot)
{
	//1. pTemp临时存储pRoot的pRight
	TreeNode<T>* pTemp = pRoot->pRight;
	//2. pTemp的左孩子成为pRoot的右孩子
	pRoot->pRight = pTemp->pLeft;
	//3. pRoot成为pTemp的左孩子
	pTemp->pLeft = pRoot;
	//4. 高度设置
	pRoot->height = 1 + ((_getHeight(pRoot->pLeft) > _getHeight(pRoot->pRight)) ?
		_getHeight(pRoot->pLeft) : _getHeight(pRoot->pRight));
	pTemp->height = 1 + ((_getHeight(pTemp->pLeft) > _getHeight(pTemp->pRight)) ?
		_getHeight(pTemp->pLeft) : _getHeight(pTemp->pRight));

	return pTemp;
}

template<class T>
inline TreeNode<T>* ACL_Tree<T>::LR(TreeNode<T>* pRoot)
{
	//以pRoot的pLeft为轴左旋
	pRoot->pLeft = LL(pRoot->pLeft);
	//再右旋
	return RR(pRoot);
}

template<class T>
inline TreeNode<T>* ACL_Tree<T>::RL(TreeNode<T>* pRoot)
{
	//以pRoot的pRight为轴右旋
	pRoot->pRight = RR(pRoot->pRight);
	//再左旋
	return LL(pRoot);
}

#include "ACLTree.h"

#define NUM 10
int main()
{
	int arr[NUM] = { 55,99,24,66,11,10,77,13,38,91 };

	ACL_Tree<int> a;


	for (int i = 0; i < NUM; i++)
	{
		a.Insert_Node(arr[i]);
	}

	return 0;
}

在这里插入图片描述

posted @ 2022-08-23 13:28  hugeYlh  阅读(539)  评论(0编辑  收藏  举报  来源