平衡二叉树详解(附带完整代码)
平衡二叉树:
高度的概念:距离根节点有多少层
左右子树的高度差不超过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节点应为根节点;
旋转过程:
- 根节点12右旋转(顺时针)成为8节点的右孩子。
- 8节点的右孩子成为12的左孩子。
- 8节点成为新的根节点。
RR旋转
当添加的新节点成为最小不平衡树的右孩子的右子树时产生:
规划可知8应为新的根节点:
旋转过程:
- 根节点6左旋转(逆时针),成为8的左孩子。
- 8的左孩子成为6节点的右孩子。
- 8成为新的根节点。
LR旋转
当添加的新节点成为最小不平衡树的左孩子的右子树时产生:
规划可知,7应该成为新的根节点
旋转过程:
- 7节点左旋成为10的相邻左孩子。
- 6节点成为7节点的左孩子。
- 根节点右旋成为7节点的相邻右孩子。
- 7节点的右孩子成为10节点的左孩子。
- 7节点成为新的根节点
RL旋转
当添加的新元素成为最小不平衡树的右孩子的左子树时产生:
7应该成为根节点
旋转过程:
- 7节点右旋成为根节点的相邻右孩子。
- 8节点成为7节点的右孩子。
- 根节点左旋成为7的相邻左孩子。
- 7节点的左孩子成为4节点的右孩子。
- 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; }
本文来自博客园,作者:hugeYlh,转载请注明原文链接:https://www.cnblogs.com/helloylh/p/17209730.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)