二叉树的非递归遍历和层次遍历详解

朴灿烈づ我的快乐病毒、 2022-12-12 13:44 264阅读 0赞

二叉树非递归遍历非递归的后序遍历二叉树

  1. //非递归的后续遍历二叉树
  2. void HXprint(Tree *tree){
  3. Stack s = initStack(); //初始化一个下面使用的栈
  4. treeNode *p = tree; //新建一个遍历指针
  5. treeNode *r=NULL; //辅助变量
  6. cout<<"-------"<<endl;
  7. while(p||!isEmpty(s)){
  8. //当遍历变量和栈同时为空时 表示遍历完成
  9. if(p){
  10. //p非空 就入栈 并且遍历指针更改为指向当前节点的左孩子
  11. push(s,p);
  12. p = p->lchild;
  13. }else{
  14. //p为空 表示当前节点已经没有左孩子
  15. p = getTop(s); //获取栈顶元素 也就是最后一个入栈的结点
  16. if(p->rchild && p->rchild!=r){
  17. //判断栈顶结点是否有右孩子
  18. p=p->rchild; //修改指针一直找右孩子 直到没有右孩子 或者 右孩子已经访问过
  19. }else{
  20. p = pop(s); //如果没有右孩子 或者 右孩子已经访问过了 就开始出栈栈顶元素 并且用指针p指向出栈元素
  21. cout<<p->data<<endl; //输出当前指针指向的结点
  22. r=p; //将r修改为已经访问过的右孩子 防止再次访问到右孩子
  23. p=NULL; //将p修改为空指针 防止再次入栈
  24. }
  25. }
  26. }
  27. }

逻辑解释:
按照下图和上述代码
思考一下 每一个结点都会经历入栈 出栈 那么 遍历方法的结束 就应该是,当所有的结点都已经访问过 ,并且 当前的栈为空的时候 表示所有的结点都已经输出 于是有了如下循环
在这里插入图片描述循环开始的时候,p指针指向根节点在这里插入图片描述循环三次后,应该是下图的样子
在这里插入图片描述而此时栈中应该入队了两个结点 分别是根节点和 它的左孩子结点
此时 再次循环 p 为空 p指向栈顶元素 如果过栈顶元素有右孩子 右孩子入栈 p指向右孩子 如果没有 则 输出根节点的左孩子结点 此时 再次将p指针修改为 null 这个时候 栈中只有一个根节点 并且 p结点指向空
再次进入循环 p指向栈顶 p这时有右孩子 则将右孩子入栈 修改辅助指针r指向右孩子 再次进入循环 出栈 输出元素 便是输出的右孩子元素 最后输出的是根节点元素
大家可以根据下图 分别进行一遍推演
在这里插入图片描述以上就是二叉树的后序非递归的输出方法 , 下面的非递归的先序和中序不再进行一步一步的解释 看代码中的注释就可以看懂

非递归的先序遍历二叉树

  1. //非递归算法的先序遍历
  2. void XXprint(Tree *tree){
  3. Stack s = initStack(); //初始化一个下面使用的栈
  4. treeNode *p = tree; //新建一个遍历指针
  5. while(p||!isEmpty(s)){
  6. while(p){
  7. cout<<p->data<<endl;
  8. push(s,p);
  9. p=p->lchild;
  10. }
  11. if(!isEmpty(s)){
  12. p = pop(s);
  13. p = p->rchild;
  14. }
  15. }
  16. }

非递归的中序遍历二叉树

  1. //非递归算法的中序遍历
  2. void ZXprint(Tree *tree){
  3. Stack s = initStack(); //初始化一个下面使用的栈
  4. treeNode *p = tree; //新建一个遍历指针
  5. while(p||!isEmpty(s)){
  6. while(p){
  7. push(s,p);
  8. p=p->lchild;
  9. }
  10. if(!isEmpty(s)){
  11. p = pop(s);
  12. cout<<p->data<<endl;
  13. p=p->rchild;
  14. }
  15. }
  16. }

层次遍历二叉树

  1. //层次遍历二叉树
  2. void levelprint(Tree *tree){
  3. queue<treeNode*> q; //使用c++提供的类库进行队列的定义
  4. q.push(tree); //将根节点入队
  5. while(!q.empty()){
  6. //当队不为空 循环
  7. treeNode *p = q.front(); //获取队头结点
  8. cout<<p->data<<endl; //输出队头结点
  9. q.pop(); //弹出队头
  10. if(p->lchild!=NULL) //如果队头有左孩子 左孩子入队
  11. {
  12. q.push(p->lchild);
  13. }
  14. if(p->rchild!=NULL){
  15. //如果队头有右孩子 右孩子入队
  16. q.push(p->rchild);
  17. }
  18. }
  19. }

根节点入队 进去while循环 p指向队头结点 输出队头结点 弹出队头
如果 p指向的结点有左孩子 左孩子入队 如果有右孩子 右孩子入队
第二次进入while循环 输出的即为根节点的左孩子结点 此时p指向的左孩子结点 没有左右孩子 则结束本次循环
第三次进入循环 输出的是根节点的右孩子结点 这时 p指向的结点 没有左孩子也没有右孩子 结束总循环
这样输出的便是层次遍历的遍历结果

在这里插入图片描述

总代码

  1. #include<iostream>
  2. #include<stdlib.h>
  3. #include <queue>
  4. using namespace std;
  5. typedef struct treeNode{
  6. //建立二叉树的存储结构
  7. int data;
  8. treeNode *lchild,*rchild;
  9. } Tree;
  10. typedef struct SNode{
  11. treeNode *data[100];
  12. int top;
  13. }SNode , *Stack; //非递归遍历中使用的栈的存储结构
  14. //栈的初始化
  15. Stack initStack(){
  16. Stack stack = (Stack)malloc(sizeof(SNode)); //使用c语言中的malloc函数分配空间 也可以使用new的方式
  17. stack->top = -1; //初始化栈顶指针
  18. return stack;
  19. }
  20. //判断栈非空
  21. bool isEmpty(Stack s){
  22. //栈的相关方法的重写
  23. if(s->top == -1){
  24. return true;
  25. }else{
  26. return false;
  27. }
  28. }
  29. //入栈
  30. void push(Stack &s , treeNode *node) //将一个树结点入栈
  31. {
  32. s->top++;
  33. s->data[s->top] = node;
  34. }
  35. //出栈
  36. treeNode *pop(Stack &s) //出栈的同时返回出栈的结点
  37. {
  38. if(s->top == -1){
  39. return false;
  40. }
  41. treeNode *temp = s->data[s->top];
  42. s->top--;
  43. return temp;
  44. }
  45. //获取栈顶结点
  46. treeNode *getTop(Stack &s){
  47. if(s->top!=-1){
  48. treeNode *node = s->data[s->top]; //获取栈顶部的结点 但是不出栈
  49. return node;
  50. }
  51. }
  52. //二叉树初始化方法
  53. Tree *initTree(treeNode *root,int data){
  54. root->lchild = NULL; //初始化根节点的左右孩子指针域
  55. root->rchild = NULL;
  56. root->data = data; //根节点赋值
  57. return root;
  58. }
  59. //插入一个左孩子结点
  60. bool insertlchild(Tree *tree,int data){
  61. treeNode *l = (treeNode*)malloc(sizeof(treeNode));
  62. l->data = data;
  63. l->lchild = NULL;
  64. l->rchild = NULL;
  65. tree->lchild = l;
  66. return true;
  67. }
  68. //插入一个右孩子结点
  69. bool insertrchild(Tree *tree,int data){
  70. treeNode *r = new treeNode;
  71. r->data = data;
  72. r->rchild = NULL;
  73. r->lchild = NULL;
  74. tree->rchild = r;
  75. }
  76. //递归遍历输出二叉树
  77. void print (Tree *tree){
  78. if(tree)
  79. {
  80. print(tree->lchild);
  81. cout << tree->data<<endl;
  82. print(tree->rchild);
  83. }
  84. }
  85. //非递归的后续遍历二叉树
  86. void HXprint(Tree *tree){
  87. Stack s = initStack(); //初始化一个下面使用的栈
  88. treeNode *p = tree; //新建一个遍历指针
  89. treeNode *r=NULL; //辅助变量
  90. cout<<"-------"<<endl;
  91. while(p||!isEmpty(s)){
  92. //当遍历变量和栈同时为空时 表示遍历完成
  93. if(p){
  94. //p非空 就入栈 并且遍历指针更改为指向当前节点的左孩子
  95. push(s,p);
  96. p = p->lchild;
  97. }else{
  98. //p为空 表示当前节点已经没有左孩子
  99. p = getTop(s); //获取栈顶元素 也就是最后一个入栈的结点
  100. if(p->rchild && p->rchild!=r){
  101. //判断栈顶结点是否有右孩子
  102. p=p->rchild; //修改指针一直找右孩子 直到没有右孩子 或者 右孩子已经访问过
  103. }else{
  104. p = pop(s); //如果没有右孩子 或者 右孩子已经访问过了 就开始出栈栈顶元素
  105. cout<<p->data<<endl; //输出当前指针指向的结点
  106. r=p; //将r修改为已经访问过的右孩子 防止再次访问到右孩子
  107. p=NULL; //将p修改为空指针 防止再次入栈
  108. }
  109. }
  110. }
  111. }
  112. //非递归算法的先序遍历
  113. void XXprint(Tree *tree){
  114. Stack s = initStack(); //初始化一个下面使用的栈
  115. treeNode *p = tree; //新建一个遍历指针
  116. while(p||!isEmpty(s)){
  117. while(p){
  118. cout<<p->data<<endl;
  119. push(s,p);
  120. p=p->lchild;
  121. }
  122. if(!isEmpty(s)){
  123. p = pop(s);
  124. p = p->rchild;
  125. }
  126. }
  127. }
  128. //非递归算法的中序遍历
  129. void ZXprint(Tree *tree){
  130. Stack s = initStack(); //初始化一个下面使用的栈
  131. treeNode *p = tree; //新建一个遍历指针
  132. while(p||!isEmpty(s)){
  133. while(p){
  134. push(s,p);
  135. p=p->lchild;
  136. }
  137. if(!isEmpty(s)){
  138. p = pop(s);
  139. cout<<p->data<<endl;
  140. p=p->rchild;
  141. }
  142. }
  143. }
  144. //层次遍历二叉树
  145. void levelprint(Tree *tree){
  146. queue<treeNode*> q; //使用c++提供的类库进行队列的定义
  147. q.push(tree); //将根节点入队
  148. while(!q.empty()){
  149. //当队不为空 循环
  150. treeNode *p = q.front(); //获取队头结点
  151. cout<<p->data<<endl; //输出队头结点
  152. q.pop(); //弹出队头
  153. if(p->lchild!=NULL) //如果队头有左孩子 左孩子入队
  154. {
  155. q.push(p->lchild);
  156. }
  157. if(p->rchild!=NULL){
  158. //如果队头有右孩子 右孩子入队
  159. q.push(p->rchild);
  160. }
  161. }
  162. }
  163. int main ()
  164. {
  165. Tree *T = new Tree;
  166. initTree(T,1);
  167. insertlchild(T,2);
  168. insertrchild(T,3);
  169. insertlchild(T->lchild,4);
  170. insertrchild(T->lchild,5);
  171. insertlchild(T->rchild,6);
  172. insertrchild(T->rchild,7);
  173. cout<<"递归中序遍历二叉树"<<endl;
  174. print (T);
  175. cout<<"非递归后序遍历二叉树"<<endl;
  176. HXprint(T);
  177. cout<<"非递归先序遍历二叉树"<<endl;
  178. XXprint(T);
  179. cout<<"非递归中序遍历二叉树"<<endl;
  180. ZXprint(T);
  181. cout<<"层次遍历二叉树"<<endl;
  182. levelprint(T);
  183. return 0;
  184. }

以上代码构造的二叉树形状为

在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,264人围观)

还没有评论,来说两句吧...

相关阅读