当前位置:   article > 正文

数据结构与算法实验2——二叉树的应用_二、实验内容 使用二叉链表来实现二叉树的存储,编写以下算法: (1)二叉树的创建 (2

二、实验内容 使用二叉链表来实现二叉树的存储,编写以下算法: (1)二叉树的创建 (2

一、实验目的

1.掌握二叉树的存储实现。

2.掌握二叉树的遍历思想。

3.掌握二叉树的常见算法的程序实现。

二、实验任务

1.输入字符序列,建立二叉链表

2.中序遍历二叉树:递归算法。

3.中序遍历二叉树:非递归算法。(最好也实现先序,后序非递归算法)

4.求二叉树的高度。

5.求二叉树的叶子数。

6.借助队列实现二叉树的层次遍历。

7.在主函数中设计一个简单的菜单,调用上述算法。

三、源代码

源文件

  1. /*
  2. 实验名称:二叉树的应用
  3. 实验目的:
  4. 1.掌握二叉树的存储实现。
  5. 2.掌握二叉树的遍历思想。
  6. 3.掌握二叉树的常见算法的程序实现。
  7. 实验内容:
  8. 1.输入字符序列,建立二叉链表。
  9. 2.中序遍历二叉树:递归算法。
  10. 3.中序遍历二叉树:非递归算法。(最好也实现先序,后序非递归算法)
  11. 4.求二叉树的高度。
  12. 5.求二叉树的叶子数。
  13. 6.借助队列实现二叉树的层次遍历。
  14. 7.在主函数中设计一个简单的菜单,调用上述算法。
  15. 实验日期:2020/12/6
  16. 开发者:每天八杯水
  17. */
  18. #include "BinTree.h"
  19. int Out();
  20. pBiTree DGCreatBinTree();//递归创建二叉树
  21. void InOrder_Recursion();//递归中序遍历
  22. pBiTree CreatBTree_NRecursion();//非递归创建二叉树
  23. void InOrder_NRecursion();//非递归中序遍历
  24. int CountLever();//统计二叉树的深度
  25. int CoumtLeafNode();//统计二叉树的叶子数
  26. void LevelOrder();//层次遍历二叉树
  27. pBiTree SF();//释放空间-采用递归删除结点
  28. int main()
  29. {
  30. cout << "\n";
  31. pBiTree bt;//定义一个结点bt存放创建好的二叉树
  32. //bt=DGCreatBinTree(); //递归创建二叉链表
  33. bt= CreatBTree_NRecursion();//非递归创建
  34. bool opt = true; //是否循环的一个标志
  35. while (opt == true) {
  36. //菜单列表
  37. cout << "\n\t\t************************************\n";
  38. cout << "\t\t* WELCOM TO MY WORLD *\n";
  39. cout << "\t\t* 1. 中序遍历-递归 *\n";
  40. cout << "\t\t* 2. 中序遍历-非递归 *\n";
  41. cout << "\t\t* 3. 求二叉树的高度 *\n";
  42. cout << "\t\t* 4. 求二叉树的叶子数 *\n";
  43. cout << "\t\t* 5. 层次遍历 *\n";
  44. cout << "\t\t* 6. 释放空间 *\n";
  45. cout << "\t\t* 7. 退 出 *\n";
  46. cout << "\t\t************************************\n";
  47. //接收输入选择
  48. cout << "\t\t请选择:";
  49. char x;
  50. cin >> x;
  51. //判断用户的选择
  52. switch (x) {
  53. case '1':
  54. cout << "递归中序遍历:";
  55. InOrder_Recursion(bt);
  56. opt = Out(); //小目录选择1返回true到循环条件时再次执行主菜单;选择2返回false退出循环
  57. break;
  58. case '2':
  59. cout << "非递归中序遍历:";
  60. InOrder_NRecursion(bt);
  61. ; opt = Out(); //小目录
  62. break;
  63. case '3':
  64. cout << "该二叉树的高度为:" << CountLever(bt);
  65. opt = Out(); //小目录
  66. break;
  67. case '4':
  68. cout << "该二叉树的叶子数个数为:" << CoumtLeafNode(bt);
  69. opt = Out(); //小目录
  70. break;
  71. case '5':
  72. cout << "层次遍历该二叉树:" ;
  73. LevelOrder(bt);
  74. opt = Out(); //小目录
  75. break;
  76. case '6':
  77. if (SF(bt)==NULL)
  78. {
  79. cout << "释放成功" << endl;
  80. }
  81. else
  82. {
  83. cout << "释放失败" << endl;
  84. cout << bt->data;
  85. }
  86. opt = Out(); //小目录
  87. break;
  88. case '7':
  89. cout << "\n\t\t你选择了6\n";
  90. opt = false; //把标志位为假,就退出了循环
  91. break;
  92. default:
  93. cout << "\n\t\t输入非法,请重新选择!\n";
  94. break;
  95. }
  96. }
  97. cout << "\n\t\t菜单已退出!\n";
  98. }

头文件

  1. #pragma once
  2. #include <stdio.h>
  3. #include <iostream>
  4. #include <queue>
  5. #include <stack>
  6. using namespace std;
  7. /*
  8. 定义小目录-进入算法后如何退出的实现
  9. */
  10. int Out() {
  11. cout << "\n";
  12. cout << "\t\t************\n";
  13. cout << "\t\t*1.返回菜单*\n";
  14. cout << "\t\t*2.退出程序*\n";//退出,程序结束
  15. cout << "\t\t************\n";
  16. cout << "\t\t选择:";
  17. char y;
  18. cin >> y; //接受输入
  19. switch (y) {
  20. case '1':
  21. return true;
  22. case '2':
  23. return false;
  24. default:
  25. cout << "\t\t非法输入,已返回主目录!\n";//输入其他数字无效
  26. return true;
  27. break;
  28. }
  29. }
  30. /*
  31. 结构类型定义
  32. */
  33. #define ElemType char // 元素类型
  34. typedef struct BiTNode
  35. {
  36. ElemType data;
  37. BiTNode* Lchild, * Rchild;
  38. } BiTNode, * pBiTree;
  39. /*
  40. 递归创建二叉链表
  41. */
  42. //pBiTree DGCreatBinTree()
  43. //{
  44. // pBiTree bt;//根结点
  45. // cout << "\t\t请输入字符建立二叉链表:";
  46. // ElemType data;
  47. // cin >> data;
  48. // if (data == '@')
  49. // bt = NULL;
  50. // else
  51. // {
  52. // bt = (pBiTree)malloc(sizeof(struct BiTNode));
  53. // bt->data = data;
  54. // bt->Lchild = DGCreatBinTree();
  55. // bt->Rchild = DGCreatBinTree();
  56. // }
  57. // return bt;
  58. //}
  59. /*
  60. 非递归创建二叉链表
  61. */
  62. pBiTree CreatBTree_NRecursion()//非递归创建二叉树-需要使用链队列
  63. {
  64. pBiTree bt,s,p;
  65. bt = NULL;
  66. int count = -1;//计数器-结点编号
  67. queue<pBiTree>squeue;
  68. cout << "\t\t请输入字符创建二叉树(@代表空)以#号键结束:";
  69. char ch;
  70. ch = getchar();
  71. while (ch!='#')
  72. {
  73. s = NULL;//这里设置的原因是:如果接下来的ch是虚结点,就会跳过赋值,那么该结构体类型的指针为空了
  74. if (ch != '@')//判断输入的字符是正常地还是表示空的结点
  75. {
  76. s = (pBiTree)malloc(sizeof(BiTNode));//*************需要释放空间--递归删除结点**********
  77. s->data = ch;
  78. s->Lchild = s->Rchild = NULL;
  79. }
  80. squeue.push(s);
  81. count++;
  82. if (count == 0)bt = s;//根结点编号为0
  83. else//count为奇数,是左孩子;偶数是右孩子
  84. {
  85. p = squeue.front();//取出-作为父结点
  86. if(s!=NULL && p!=NULL)//
  87. if (count % 2 == 1) { p->Lchild = s; }//如果s为@,p左孩子就是空的,奇数就把从队列中取出来的结点左孩子指向它
  88. else { p->Rchild = s; }
  89. if (count % 2 == 0) { squeue.pop(); } //该结点左右孩子已经赋值完毕,可以出队列了
  90. }
  91. ch = getchar();
  92. }
  93. return bt;
  94. }
  95. /*
  96. 递归中序
  97. */
  98. void InOrder_Recursion(pBiTree bt)
  99. {
  100. if (bt == NULL)return;
  101. InOrder_Recursion(bt->Lchild);
  102. cout << bt->data;
  103. InOrder_Recursion(bt->Rchild);
  104. }
  105. /*
  106. 非递归中序
  107. */
  108. void InOrder_NRecursion(pBiTree bt)//需要使用栈
  109. {
  110. stack<pBiTree>sstack;
  111. pBiTree p;
  112. p = bt;
  113. if (p == NULL)return;
  114. sstack.push(bt);
  115. p = p->Lchild;
  116. while (p||!sstack.empty())//栈为空返回的0,所以加上!
  117. {
  118. while (p != NULL)//一直入栈左孩子直到为空
  119. {
  120. sstack.push(p);
  121. p = p->Lchild;
  122. }//循环最后一次p为空的左孩子
  123. p = sstack.top();//给p赋值为栈顶元素->也就是上面那个空的左孩子的父结点 所以取出来输出
  124. sstack.pop();//因为该栈顶元素的左孩子为空,所以按照中序遍历,下一个应该是D结点,其次是R结点,
  125. cout << p->data;
  126. p = p->Rchild;//左孩子为空,就返回到
  127. }
  128. }
  129. /*
  130. 统计二叉树的深度
  131. */
  132. int CountLever(pBiTree bt)//递归思想
  133. {
  134. if (bt == NULL)return 0;//左孩子为空返回个数0,右孩子为空返回0.一次循环结束返回值为1
  135. else
  136. {
  137. int i = CountLever(bt->Lchild);//一直递归到根结点最后一个左孩子、结束该递归条件是左孩子为空
  138. int j = CountLever(bt->Rchild);//当上一条左孩子为空时,进入右孩子
  139. return(i > j ? i : j) + 1;//三目运算符
  140. }
  141. }
  142. /*
  143. 统计二叉树的叶子数
  144. */
  145. int CoumtLeafNode(pBiTree bt)//有个数的前提条件是该结点的左右孩子都为空时个数加1
  146. {
  147. if (bt == NULL)return 0;
  148. else if ((bt->Lchild == NULL) && (bt->Rchild == NULL))return 1;//只要遇见一个左右孩子都是空的结点就个数加1
  149. else
  150. return(CoumtLeafNode(bt->Lchild) + CoumtLeafNode(bt->Rchild));//相当于兵分两路,从根结点左孩子和右孩子分别进入
  151. }
  152. /*
  153. 层次遍历二叉树
  154. */
  155. void LevelOrder(pBiTree bt)//使用队列思想-与非递归建立二叉树思想相同,根结点先入队列,再取队头元素为索引,若孩子不空,把索引左右孩子依次入队,该索引用了就出队
  156. {
  157. queue<pBiTree>squeue;
  158. if (bt == NULL)return;
  159. pBiTree p;
  160. p = bt;
  161. squeue.push(bt);
  162. while (!squeue.empty())//栈空循环结束
  163. {
  164. p = squeue.front();
  165. squeue.pop();
  166. cout << p->data;
  167. if(p->Lchild != NULL)//左孩子入队列
  168. squeue.push(p->Lchild);
  169. if(p->Rchild != NULL)//紧接着右孩子入队列
  170. squeue.push(p->Rchild);
  171. }
  172. }
  173. pBiTree SF(pBiTree bt)
  174. {
  175. if (bt == NULL)return bt;
  176. SF(bt->Lchild);
  177. //cout << bt->data;
  178. SF(bt->Rchild);
  179. free(bt);
  180. bt = NULL;//
  181. return bt;
  182. }

四、运行结果

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/972640
推荐阅读
相关标签
  

闽ICP备14008679号