当前位置:   article > 正文

二叉树遍历的非递归算法_二叉树的遍历,非递归算法

二叉树的遍历,非递归算法

非递归的算法主要采用的是循环出栈入栈来实现对二叉树的遍历,下面是过程分析

以下列二叉树为例:(图片来自懒猫老师《数据结构》课程相关内容)

1.前序遍历

前序遍历的顺序为:根结点->左子树->右子树

基本过程:

(1)访问根结点,将根结点入栈

(2)循环逐个访问左子树,执行(1)中步骤;当访问到没有左子树的结点时,跳出循环

(3)栈不为空,根结点出栈,访问右子树

这里以A的左子树为例进行栈的变化过程说明:

可以总结成,没有左子树->出栈+右子树入栈;没有右子树->出栈

代码实现:

  1. void PreOrder(BiNode *bt) { //树的前序遍历
  2. SqStack s;
  3. s = InitStack();
  4. BiNode *p = bt;
  5. while (p != NULL || StackEmpty(&s) != 1) { //当p为空,栈也为空时退出循环
  6. while (p != NULL) {
  7. visit(p->data);//访问根结点
  8. Push(&s, p); //将指针p的节点压入栈中
  9. p = p->Lchild; //遍历左子树
  10. }
  11. if (StackEmpty(&s) != 1) { //栈不为空
  12. p = Pop(&s); //根结点出栈,相当于回退
  13. p = p->rchild; //遍历右子树
  14. }
  15. }
  16. DestroyStack(&s);
  17. }

2.中序遍历

中序遍历的顺序为:左子树->根结点>右子树

基本过程:

(1)将根结点入栈

(2)循环逐个访问左子树,执行(1)中步骤;当访问到没有左子树的结点时,跳出循环

(3)栈不为空,根结点出栈,访问根结点,再访问右子树

其实就是将访问根结点的位置换了

代码实现:

  1. void MidOrder(BiNode *bt) { //树的中序遍历
  2. SqStack s;
  3. s = InitStack();
  4. BiNode *p = bt;
  5. while (p != NULL || StackEmpty(&s) != 1) { //当p为空,栈也为空时退出循环
  6. while (p != NULL) {
  7. Push(&s, p); //将指针p的节点压入栈中
  8. p = p->Lchild; //遍历左子树
  9. }
  10. if (StackEmpty(&s) != 1) { //栈不为空
  11. p = Pop(&s); //根结点出栈,相当于回退
  12. visit(p->data);//访问根结点
  13. p = p->rchild; //遍历右子树
  14. }
  15. }
  16. DestroyStack(&s);
  17. }

3.后序遍历

 前两种遍历的栈数据类型都是BiNode *,但后序遍历的栈的数据类型要进行重新定义,因为后序遍历的顺序是左子树->右子树>根结点,结点要进入两次栈,出两次栈,为什么会有两次呢?

(1)第一次出栈:只遍历完左子树,该结点不能出栈,需要第二次入栈;找到右子树并遍历

(2)第二次出栈:遍历完左右子树,该结点出栈,并访问

需要注意的是,第二次出栈并访问之后,需要将p指针置空,这样才能在下一次循环的时候,重新从栈中取到一个元素(或者理解成二叉树中的回退操作)

这里设置一个flag标志来区分两次出入栈,并进行不同的操作

栈元素类型定义如下:

  1. typedef struct element {
  2. BiNode *ptr;
  3. int flag;
  4. } element;

代码实现:

(因为后序遍历和前两种数据类型不一样,这里定义了两套栈函数分别来用,用_1下标区分)

  1. void PostOrder(BiNode *bt) { //树的后序遍历
  2. SqStack s;
  3. s = InitStack_1();
  4. BiNode *p = bt;
  5. element elem;
  6. while (p != NULL || StackEmpty_1(&s) != 1) { //当p为空,栈也为空时退出循环
  7. if (p != NULL) {//第一次入栈,访问左子树
  8. elem.ptr = p;
  9. elem.flag = 1; //标记flag为1,表示即将第一次入栈
  10. Push_1(&s, elem); //将指针p的结点第一次压入栈中
  11. p = p->Lchild;
  12. } else {
  13. elem = Pop_1(&s); //出栈
  14. p = elem.ptr; //p指向当前要处理的结点
  15. if (elem.flag == 1) {
  16. //flag==1时,说明只访问过左子树,还要访问右子树
  17. elem.flag = 2;
  18. Push_1(&s, elem); //结点第二次压入栈中
  19. p = p->rchild;
  20. } else {
  21. //flag==2时,左右子树都已经访问过了
  22. visit(p->data);
  23. p = NULL; //访问后,p赋为空,确保下次循环时继续出栈(相当于回退)
  24. }
  25. }
  26. }
  27. DestroyStack_1(&s);
  28. }

4. 完整代码

分为三个文件包,一个是存放栈的操作函数,一个是存放二叉树的非递归遍历函数,一个是对二叉树的非递归遍历功能进行的测试,第三个文件调用前两个头文件就可以测试完整功能

(1)数组堆栈_二叉树非递归.h

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #define STACK_INIT_SIZE 100
  5. #define STACKINCREMENT 10
  6. typedef char Datatype;
  7. typedef struct BiNode {
  8. Datatype data;//数据内容
  9. struct BiNode *Lchild;//指向左孩子结点
  10. struct BiNode *rchild;//指向右孩子结点
  11. } BiNode;
  12. typedef BiNode *Elemtype;
  13. typedef struct element {
  14. BiNode *ptr;
  15. int flag;
  16. } element;
  17. typedef element Elemtype_1;
  18. typedef struct {
  19. Elemtype *data;//用于前序和中序遍历
  20. Elemtype_1 *data_1;//用于后序遍历
  21. int top;//栈顶指针,这里用int类型表示指针的下标
  22. int stacksize;
  23. } SqStack;
  24. Elemtype Pop(SqStack *s);
  25. SqStack InitStack() {//空栈构造函数
  26. SqStack s;
  27. s.data = (Elemtype *)malloc(STACK_INIT_SIZE * sizeof(Elemtype));
  28. s.top = -1; //表示栈空
  29. s.stacksize = STACK_INIT_SIZE;
  30. if (s.data != NULL)
  31. {}
  32. else
  33. printf("Init error!\n");
  34. return s;
  35. }
  36. void DestroyStack(SqStack *s) {//销毁栈函数
  37. free(s->data);
  38. }
  39. int StackEmpty(SqStack *s) {//判断是否为空栈,是返回1,否 返回0
  40. if (s->top == -1)
  41. return 1;
  42. else
  43. return 0;
  44. }
  45. void Push(SqStack *s, Elemtype e) {//添加元素入栈
  46. if (s->top >= s->stacksize) {
  47. s->data = (Elemtype *)malloc((STACK_INIT_SIZE + STACKINCREMENT) * sizeof(Elemtype));
  48. s->stacksize += STACKINCREMENT;
  49. if (s->data != NULL) {}
  50. else
  51. printf("Push error!\n");
  52. } else {
  53. s->top++;
  54. s->data[s->top] = e;
  55. }
  56. }
  57. Elemtype Pop(SqStack *s) {
  58. if (StackEmpty(s) != 1 && s->top >= 0) {
  59. Elemtype e = s->data[s->top];
  60. s->top--;
  61. return e;
  62. }
  63. printf("Pop error!\n");
  64. }
  65. SqStack InitStack_1() {//空栈构造函数
  66. SqStack s;
  67. s.data_1 = (Elemtype_1 *)malloc(STACK_INIT_SIZE * sizeof(Elemtype_1));
  68. s.top = -1; //表示栈空
  69. s.stacksize = STACK_INIT_SIZE;
  70. if (s.data != NULL)
  71. {}
  72. else
  73. printf("Init error!\n");
  74. return s;
  75. }
  76. void DestroyStack_1(SqStack *s) {//销毁栈函数
  77. free(s->data_1);
  78. }
  79. int StackEmpty_1(SqStack *s) {//判断是否为空栈,是返回1,否 返回0
  80. if (s->top == -1)
  81. return 1;
  82. else
  83. return 0;
  84. }
  85. void Push_1(SqStack *s, Elemtype_1 e) {//添加元素入栈
  86. if (s->top >= s->stacksize) {
  87. s->data_1 = (Elemtype_1 *)malloc((STACK_INIT_SIZE + STACKINCREMENT) * sizeof(Elemtype_1));
  88. s->stacksize += STACKINCREMENT;
  89. if (s->data_1 != NULL) {}
  90. else
  91. printf("Push error!\n");
  92. } else {
  93. s->top++;
  94. s->data_1[s->top] = e;
  95. }
  96. }
  97. Elemtype_1 Pop_1(SqStack *s) {
  98. if (StackEmpty(s) != 1 && s->top >= 0) {
  99. Elemtype_1 e = s->data_1[s->top];
  100. s->top--;
  101. return e;
  102. }
  103. printf("Pop error!\n");
  104. }

 (2)二叉树遍历(非递归).h

  1. #include "数组堆栈_二叉树非递归.h"
  2. BiNode *Creat(char *str, int *i, int len) { //树的创建
  3. struct BiNode *bt = NULL;
  4. char ch = str[(*i)++];
  5. if (ch == '#' || *i >= len) {
  6. bt = NULL;
  7. } else {
  8. bt = (struct BiNode *)malloc(sizeof(BiNode));
  9. if (bt != NULL) {
  10. bt->data = ch;
  11. bt->Lchild = Creat(str, i, len); //这里的递归要赋值,这样才能建立不同域中的连接关系
  12. bt->rchild = Creat(str, i, len);
  13. }
  14. }
  15. return bt;//返回的一直是根结点
  16. }
  17. void visit(Datatype e) {
  18. printf("%c ", e);
  19. }
  20. void PreOrder(BiNode *bt) { //树的前序遍历
  21. SqStack s;
  22. s = InitStack();
  23. BiNode *p = bt;
  24. while (p != NULL || StackEmpty(&s) != 1) { //当p为空,栈也为空时退出循环
  25. while (p != NULL) {
  26. visit(p->data);//访问根结点
  27. Push(&s, p); //将指针p的节点压入栈中
  28. p = p->Lchild; //遍历左子树
  29. }
  30. if (StackEmpty(&s) != 1) { //栈不为空
  31. p = Pop(&s); //根结点出栈,相当于回退
  32. p = p->rchild; //遍历右子树
  33. }
  34. }
  35. DestroyStack(&s);
  36. }
  37. void MidOrder(BiNode *bt) { //树的中序遍历
  38. SqStack s;
  39. s = InitStack();
  40. BiNode *p = bt;
  41. while (p != NULL || StackEmpty(&s) != 1) { //当p为空,栈也为空时退出循环
  42. while (p != NULL) {
  43. Push(&s, p); //将指针p的节点压入栈中
  44. p = p->Lchild; //遍历左子树
  45. }
  46. if (StackEmpty(&s) != 1) { //栈不为空
  47. p = Pop(&s); //根结点出栈,相当于回退
  48. visit(p->data);//访问根结点
  49. p = p->rchild; //遍历右子树
  50. }
  51. }
  52. DestroyStack(&s);
  53. }
  54. void PostOrder(BiNode *bt) { //树的后序遍历
  55. SqStack s;
  56. s = InitStack_1();
  57. BiNode *p = bt;
  58. element elem;
  59. while (p != NULL || StackEmpty_1(&s) != 1) { //当p为空,栈也为空时退出循环
  60. if (p != NULL) {//第一次入栈,访问左子树
  61. elem.ptr = p;
  62. elem.flag = 1; //标记flag为1,表示即将第一次入栈
  63. Push_1(&s, elem); //将指针p的结点第一次压入栈中
  64. p = p->Lchild;
  65. } else {
  66. elem = Pop_1(&s); //出栈
  67. p = elem.ptr; //p指向当前要处理的结点
  68. if (elem.flag == 1) {
  69. //flag==1时,说明只访问过左子树,还要访问右子树
  70. elem.flag = 2;
  71. Push_1(&s, elem); //结点第二次压入栈中
  72. p = p->rchild;
  73. } else {
  74. //flag==2时,左右子树都已经访问过了
  75. visit(p->data);
  76. p = NULL; //访问后,p赋为空,确保下次循环时继续出栈(相当于回退)
  77. }
  78. }
  79. }
  80. DestroyStack_1(&s);
  81. }

 (3)二叉树遍历(非递归).c

  1. #include "二叉树遍历(非递归).h"
  2. main() {
  3. printf("测试二叉树遍历(非递归)算法\n");
  4. printf("建立一个二叉树-->");
  5. BiNode *bt;
  6. int i = 0, len;
  7. char str[50];
  8. printf("输入一个字符串用于建立二叉树:");
  9. scanf("%s", str);
  10. len = strlen(str);
  11. bt = Creat(str, &i, len);
  12. printf("测试遍历操作:\n");
  13. printf("测试树的前序遍历:");
  14. PreOrder(bt);
  15. printf("\n");
  16. printf("测试树的中序遍历:");
  17. MidOrder(bt);
  18. printf("\n");
  19. printf("测试树的后序遍历:");
  20. PostOrder(bt);
  21. printf("\n");
  22. }

5.测试输出

 初学小白,有错误的话欢迎指正喔!~

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

闽ICP备14008679号