鱼C论坛

 找回密码
 立即注册
查看: 2016|回复: 8

[技术交流] 平衡二叉树C++实现(萌新分享)

[复制链接]
发表于 2020-7-7 10:47:13 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 昨非 于 2020-8-8 10:56 编辑

   初学编程,参考前辈指导完成,定有不足之处,敬请指出,初来乍到,请多关照。

测试效果图如下:

                               
登录/注册后可看大图



                               
登录/注册后可看大图



                               
登录/注册后可看大图


代码清单及注释如下:
  1. /*
  2. Author:昨非
  3. Date:2020.5.21
  4. */



  5. #include <iostream>
  6. #include <algorithm>
  7. using namespace std;

  8. //结点结构体            
  9. template<class T>
  10. class BiNode
  11. {
  12. public:
  13.         T data;
  14.         BiNode <T>* lch;
  15.         BiNode <T>* rch;
  16.         int height;           //节点高度,判断平衡关键
  17.         BiNode<T>(const T _data) : data(_data), lch(NULL), rch(NULL), height(0) {}  //初始化
  18. };
  19. //平衡二叉树类
  20. template<class T>
  21. class AVLTree
  22. {
  23. public:
  24.         BiNode<T>* root;

  25.         AVLTree<T>() { root = NULL; }                     //默认构造
  26.         void CreateAVL(T a[], int n);                     //建树
  27.         void InsertAVL(BiNode<T>*& R, T key);            //插入
  28.         BiNode<T>* SearchAVL(BiNode<T>* R, T key);       //按值查找
  29.         BiNode<T>* DeleteAVL(BiNode<T>*& R, T key);      //按值删除
  30.         void Inorder(BiNode<T>* R);                      //中序遍历检验
  31.         void printAVLTree(BiNode<T>* root, int height, ostream& out);//直观打印
  32.         ~AVLTree<T>()                                    //递归析构
  33.         {
  34.                 Release(root);
  35.                 cout << "平衡二叉树已销毁!(析构)" << endl;
  36.         }

  37. private:
  38.         int GetHeight(BiNode<T>* t);                 //求结点的高度
  39.         BiNode<T>* LL(BiNode<T>* t);            //单旋转 左
  40.         BiNode<T>* RR(BiNode<T>* t);                   //单旋转 右
  41.         BiNode<T>* LR(BiNode<T>* t);                   //双旋转 右左
  42.         BiNode<T>* RL(BiNode<T>* t);            //双旋转 左右
  43.         void Release(BiNode<T>* R);                   //析构辅助函数
  44.         BiNode<T>* MinNode(BiNode<T>* t) const;       //获取树中的最小值 辅助判断
  45.         BiNode<T>* MaxNode(BiNode<T>* t) const;       //获取树中的最大值 辅助判断
  46. };
  47. //获取树中的最小值 辅助判断
  48. template<class T>
  49. BiNode<T>* AVLTree<T>::MinNode(BiNode<T>* t) const
  50. {
  51.         if (NULL == t)
  52.         {
  53.                 return NULL;
  54.         }
  55.         while (NULL != t->lch)
  56.         {
  57.                 t = t->lch;
  58.         }
  59.         return t;
  60. }

  61. //获取树中的最大值 辅助判断
  62. template<class T>
  63. BiNode<T>* AVLTree<T>::MaxNode(BiNode<T>* t) const
  64. {
  65.         if (NULL == t)
  66.         {
  67.                 return NULL;
  68.         }
  69.         while (NULL != t->rch)
  70.         {
  71.                 t = t->rch;
  72.         }
  73.         return t;
  74. }

  75. //获得结点高度 辅助判断
  76. template <class T>
  77. int AVLTree<T>::GetHeight(BiNode<T>* t)
  78. {
  79.         if (t == NULL)
  80.                 return -1;
  81.         else
  82.                 return t->height;
  83. }

  84. //建树 :循环调用InsertAVL
  85. template<class T>
  86. void AVLTree<T>::CreateAVL(T a[], int n)
  87. {
  88.         for (int i = 0; i < n; i++)
  89.         {
  90.                 InsertAVL(root, a[i]);
  91.         }
  92.         cout << "平衡二叉树构造完成!" << endl;
  93. }

  94. //插入函数
  95. template<class T>
  96. void AVLTree<T>::InsertAVL(BiNode<T>*& R, T key)
  97. {
  98.         if (R == NULL)    //结点为空
  99.         {
  100.                 R = new BiNode<T>(key);
  101.         }//判断当前结点应该插入根节点的左子树还是右子树
  102.         else if (key < R->data)
  103.         {
  104.                 InsertAVL(R->lch, key);
  105.                               //判断平衡情况
  106.                 if ((GetHeight(R->lch) - GetHeight(R->rch)) > 1)//插入后失衡
  107.                 {
  108.                         if (key < R->lch->data)
  109.                         {
  110.                                 R = RR(R);//左左的旋转
  111.                         }
  112.                         else
  113.                                 R = LR(R);//左右的旋转
  114.                 }
  115.         }
  116.         else if (key > R->data)
  117.         {
  118.                 InsertAVL(R->rch, key);
  119.                 if ((GetHeight(R->rch) - GetHeight(R->lch)) > 1)// 右插后失衡
  120.                 {
  121.                         if (key < R->rch->data)
  122.                         {
  123.                                 R = RL(R);//右左
  124.                         }
  125.                         else
  126.                                 R = LL(R); //右右
  127.                 }
  128.         }
  129.         R->height = max(GetHeight(R->lch), GetHeight(R->rch)) + 1;
  130. }

  131. //按值查找  
  132. template<class T>
  133. BiNode<T>* AVLTree<T>::SearchAVL(BiNode<T>* R, T key)
  134. {
  135.         while (R != NULL)
  136.         {
  137.                 if (key == R->data)
  138.                         return R;
  139.                 else if (key < R->data)
  140.                         R = R->lch;
  141.                 else
  142.                         R = R->rch;
  143.         }
  144.         return NULL;
  145. }

  146. //删除给定值
  147. template<class T>
  148. BiNode<T>* AVLTree<T>::DeleteAVL(BiNode<T>*& R, T key)
  149. {
  150.         if (NULL == R)   //空
  151.         {
  152.                 return NULL;
  153.         }
  154.         if (key < R->data)
  155.         {
  156.                 R->lch = DeleteAVL(R->lch, key);
  157.                 //相当于在右子树上插入节点
  158.                 if (GetHeight(R->rch) - GetHeight(R->lch) == 2)
  159.                 {
  160.                         //相当于在右子树上插入左节点造成的失衡(情况四)
  161.                         if (GetHeight(R->rch->lch) > GetHeight(R->rch->rch))
  162.                         {
  163.                                 R = RL(R);//相当与插入的右左
  164.                         }
  165.                         else
  166.                         {
  167.                                 R = RR(R);//相当于插入的右右
  168.                         }
  169.                 }
  170.         }
  171.         else if (key > R->data)
  172.         {
  173.                 R->rch = DeleteAVL(R->rch, key);
  174.                 if (GetHeight(R->lch) - GetHeight(R->rch) == 2)
  175.                 {
  176.                         //判断插入位置
  177.                         if (GetHeight(R->lch->lch) > GetHeight(R->lch->rch))
  178.                                 R = LL(R);//左左
  179.                         else
  180.                                 R = LR(R);
  181.                 }
  182.         }
  183.         else
  184.         {
  185.                 //1 当前节点是不是叶节点
  186.                 //2 删除之后还要看看是否破坏了平衡性
  187.                 if (NULL != R->lch && NULL != R->rch)
  188.                 {
  189.                         if (GetHeight(R->lch) > GetHeight(R->rch))//左边子树高度大
  190.                         {
  191.                                 BiNode<T>* _MaxNode = MaxNode(R->lch);//获取左结点最大值
  192.                                 R->data = _MaxNode->data;
  193.                                 R->lch = DeleteAVL(R->lch, _MaxNode->data);
  194.                         }
  195.                         else
  196.                         {
  197.                                 BiNode<T>* _MinNode = MinNode(R->rch);
  198.                                 R->data = _MinNode->data;
  199.                                 R->rch = DeleteAVL(R->rch, _MinNode->data);
  200.                         }
  201.                 }
  202.                 else     //只有一个为NULL
  203.                 {
  204.                         BiNode<T>* NowNode = R;
  205.                         if (NULL != R->lch)
  206.                         {
  207.                                 R = R->lch;
  208.                         }
  209.                         else if (NULL != R->rch)
  210.                         {
  211.                                 R = R->rch;
  212.                         }
  213.                         else
  214.                         {
  215.                                 R = NULL;// 当前节点是叶节点没有子节点
  216.                         }
  217.                         delete NowNode;
  218.                 }
  219.         }
  220.         return R;//返回该结点
  221. }

  222. //左左插入导致的不平衡  ->顺时针
  223. template <typename T>
  224. BiNode<T>* AVLTree<T>::LL(BiNode<T>* t)
  225. {
  226.         BiNode<T>* q = t->rch;
  227.         t->rch = q->lch;
  228.         q->lch = t;
  229.         t->height = max(GetHeight(t->lch), GetHeight(t->rch)) + 1;
  230.         q->height = max(GetHeight(q->lch), GetHeight(q->rch)) + 1;
  231.         return q;
  232. }

  233. //右右插入导致的不平衡  ->逆时针
  234. template <typename T>
  235. BiNode<T>* AVLTree<T>::RR(BiNode<T>* t)
  236. {
  237.         BiNode<T>* q = t->lch;
  238.         t->lch = q->rch;
  239.         q->rch = t;
  240.         t->height = max(GetHeight(t->lch), GetHeight(t->rch)) + 1;
  241.         q->height = max(GetHeight(q->lch), GetHeight(q->rch)) + 1;
  242.         return q;
  243. }

  244. //插入点位于t的左儿子的右子树   ->先逆再顺
  245. template <typename T>
  246. BiNode<T>* AVLTree<T>::LR(BiNode<T>* t)
  247. {  
  248.         t->lch = LL(t->lch);
  249.         return RR(t);
  250. }

  251. //插入点位于t的右儿子的左子树    ->先顺再逆
  252. template <typename T>
  253. BiNode<T>* AVLTree<T>::RL(BiNode<T>* t)
  254. {  
  255.         t->rch = RR(t->rch);
  256.         return LL(t);
  257. }

  258. //中序遍历用以验证
  259. template<class T>
  260. void AVLTree<T>::Inorder(BiNode<T>* R)
  261. {
  262.         if (R != NULL)
  263.         {
  264.                 Inorder(R->lch);
  265.                 cout << R->data << "  ";
  266.                 Inorder(R->rch);
  267.         }
  268. }

  269. //递归调用用以析构
  270. template<class T>
  271. void AVLTree<T>::Release(BiNode<T>* R)
  272. {
  273.         if (R != NULL)
  274.         {
  275.                 Release(R->lch);
  276.                 Release(R->rch);
  277.                 delete R;
  278.         }
  279. }

  280. //递归实现直观打印
  281. template<class T>
  282. void AVLTree<T>::printAVLTree(BiNode<T>* root, int height, ostream& out)
  283. {
  284.         char branches[] = { " /\\<" };    //树枝
  285.         if (root != NULL)
  286.         {   //打印当前结点右子树,深度+1
  287.                 printAVLTree(root->rch, height + 1, out);  //递归
  288.                 for (int i = 0; i < height; i++) out << "\t";//根据深度,右移
  289.                 out << "(" << root->data << ")";
  290.                 //打印树枝
  291.                 out << branches[((root->lch != NULL) << 1) | (root->rch != NULL)];
  292.                 out << endl;//换行,打印当前结点的左子树
  293.                 printAVLTree(root->lch, height + 1, out);  //递归
  294.         }
  295. }

  296. int main()              //测试
  297. {
  298.         int a[] = { 63, 90, 70, 55, 67, 42, 98 };//测试数据
  299.         AVLTree<int>avltree;               //默认构造

  300.         avltree.CreateAVL(a, 7);          //依据数组建树
  301.         cout << "当前测试数据,整型 { 63, 90, 70, 55, 67, 42, 98 }; " << endl;
  302.         cout << "查找测试数据:67" << endl << "插入测试数据:101" << endl << "测试删除数据:70" << endl;
  303.         cout << "**********************************************************" << endl;
  304.         cout << "原平衡二叉树中序遍历如下:";
  305.         avltree.Inorder(avltree.root);   
  306.         cout << endl;
  307.         cout << "打印如下:" << endl;
  308.         avltree.printAVLTree(avltree.root, 0, cout);   
  309.         cout << endl << endl;
  310.        
  311.         cout << "***************************************************\n";
  312.         cout << " *    │1.打印AVL树       2.插入给定值      │    *\n";
  313.         cout << " *    │                                    │    *\n";
  314.         cout << " *    │3.删除给定值      4.中序遍历检验    │    *\n";
  315.         cout << " *    │                                    │    *\n";
  316.         cout << " *    │5.查找给定值      6.退出程序        │    *\n";
  317.         cout << "***************************************************\n";
  318.         cout << endl;
  319.         BiNode<int>* p = avltree.SearchAVL(avltree.root, 67);   //初始化查找指针,避免被case标签跳过
  320.         int select;
  321.         do
  322.         {
  323.                 cout << "请选择操作方式 (1~6):" << endl;
  324.                 cin >> select;
  325.                 if (select > 6)
  326.                         cout << "错误操作,请重新输入!"<<endl;
  327.                 else
  328.                
  329.                 switch (select) {

  330.                 case 1:
  331.                         avltree.printAVLTree(avltree.root, 0, cout);
  332.                         cout << endl << endl;
  333.                         break;

  334.                 case 2:
  335.                         avltree.InsertAVL(avltree.root, 101);
  336.                         cout << "插入成功!" << endl;
  337.                         break;

  338.                 case 3:
  339.                         avltree.DeleteAVL(avltree.root, 70);
  340.                         cout << "删除成功!" << endl;
  341.                         break;

  342.                 case 4:
  343.                         cout << "中序遍历结果:";
  344.                         avltree.Inorder(avltree.root);
  345.                         cout << endl << endl;
  346.                         break;

  347.                 case 5:
  348.                         cout << "查找AVL: ";
  349.                         if (p != NULL)
  350.                                 cout << p->data << endl;
  351.                         else
  352.                                 cout << "给定值未找到" << endl;
  353.                         break;

  354.                 case 6:
  355.                         cout << "感谢使用!" << endl;
  356.                         cout << "***********************************************************" << endl;
  357.                 }
  358.         } while (select != 6);
  359.         return 0;
  360. }
复制代码






(对于上次只付上bd网盘链接的情况深感抱歉)

评分

参与人数 2荣誉 +6 鱼币 +1 贡献 +3 收起 理由
开心小傻猪 + 1 + 1 鱼C有你更精彩^_^
严凯 + 5 + 3 鱼C有你更精彩^_^

查看全部评分

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-7-22 21:14:27 | 显示全部楼层
不错
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2020-7-23 11:11:37 | 显示全部楼层

谢谢大佬的鼓励

评分

参与人数 1荣誉 +1 鱼币 +1 收起 理由
开心小傻猪 + 1 + 1 无条件支持楼主!

查看全部评分

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-8-8 10:47:30 | 显示全部楼层
之前只有一个链接确实很不礼貌,已将源码附上,希望对您有帮助

评分

参与人数 1荣誉 +1 鱼币 +1 收起 理由
开心小傻猪 + 1 + 1 鱼C有你更精彩^_^

查看全部评分

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-8-8 13:10:32 | 显示全部楼层
新增效果图(刚学会贴网络图片)

评分

参与人数 1荣誉 +1 鱼币 +1 收起 理由
开心小傻猪 + 1 + 1 鱼C有你更精彩^_^

查看全部评分

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-8-21 17:47:45 | 显示全部楼层
支持(但这不应该在数据结构板块吗???
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-12-3 19:55:43 | 显示全部楼层
好家伙

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-3-28 18:21:17 | 显示全部楼层
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2022-3-28 18:53:37 | 显示全部楼层
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-24 14:39

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表