当前位置:   article > 正文

数据结构--二叉树的非递归遍历_树的非递归后序遍历

树的非递归后序遍历

系列文章目录

第八话 数据结构之二叉树

文章目录

  • 1、前言
  • 2、非递归遍历路线
  • 3、创建二叉树
    • 先序遍历非递归实现
    • 中序遍历非递归实现
    • 后续遍历非递归实现
  • 4、总结

前言

对于同一个二叉树来说,其先序、中序、后序遍历都是从根节点开始的,且在遍历过程中经过节点的路线也是一样的,只是访问的时机不同而已。

一、非递归遍历的路线

路线图如下:

9916c51a53034ec9a9fb836e8ac25521.jpeg

沿着该路线:

按 ▲ 标记的节点读得的序列为先序序列

按  *  标记的节点读得的序列为中序序列

按  #  标记的节点读得的序列为后序序列

1、首先创建一个二叉树: 

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define maxsize 100
  4. //先序遍历非递归实现
  5. typedef char Elemtype;
  6. typedef struct node{
  7. Elemtype date;
  8. struct node *lchild,*rchild;
  9. }bitree;
  10. bitree *createtree()
  11. {
  12. bitree *pA = (bitree*)malloc(sizeof(bitree));
  13. bitree *pB = (bitree*)malloc(sizeof(bitree));
  14. bitree *pC = (bitree*)malloc(sizeof(bitree));
  15. bitree *pD = (bitree*)malloc(sizeof(bitree));
  16. bitree *pE = (bitree*)malloc(sizeof(bitree));
  17. bitree *pF = (bitree*)malloc(sizeof(bitree));
  18. bitree *pG = (bitree*)malloc(sizeof(bitree));
  19. pA->date = 'A';
  20. pB->date = 'B';
  21. pC->date = 'C';
  22. pD->date = 'D';
  23. pE->date = 'E';
  24. pF->date = 'F';
  25. pG->date = 'G';
  26. pA->lchild = pB;
  27. pA->rchild = pC;
  28. pB->lchild = NULL;
  29. pB->rchild = pD;
  30. pC->lchild = NULL;
  31. pC->rchild = pE;
  32. pD->lchild = pF;
  33. pD->rchild = pG;
  34. pE->lchild = NULL;
  35. pE->rchild = NULL;
  36. pF->lchild = NULL;
  37. pF->rchild = NULL;
  38. pG->lchild = NULL;
  39. pG->rchild = NULL;
  40. return pA;
  41. }

二、先序遍历的非递归实现

1、实现方法如下:

在沿左子树搜索时,当搜索的节点不为空时,先访问节点,然后再进栈,在搜索左节点,不为空时继续访问并且入栈,继续以此规律搜索

当搜索的节点为空时,让一个节点出栈,然后搜索节点的右节点,再为空时再出栈一个节点,并且继续搜索右子树

2、实现代码如下: 

  1. //先序遍历非递归实现
  2. void preorder(bitree *t)
  3. {
  4. bitree *Stack[maxsize];
  5. int top = -1;
  6. bitree *p;
  7. if(t==NULL){
  8. printf("树为空\n");
  9. }
  10. p = t;
  11. while(p!=NULL||top!=-1){
  12. while(p!=NULL){
  13. printf("%c ",p->date);//访问节点的数据域
  14. if(top<maxsize-1){
  15. top++;
  16. Stack[top] = p;//入栈
  17. }else{
  18. printf("错误\n");
  19. }
  20. p = p->lchild;//指向左孩子
  21. }
  22. if(top==-1){
  23. printf("空");
  24. }else{
  25. p = Stack[top];//出栈
  26. top--;
  27. p = p->rchild;//指向右孩子
  28. }
  29. }
  30. }

3、在主函数中实现如下:

  1. int main()
  2. {
  3. bitree *t;
  4. t = createtree();
  5. printf("先序遍历非递归实现:");
  6. preorder(t);
  7. printf("\n");
  8. return 0;
  9. }

e5f6ed59cd154ab89a31738bcabeec66.png

三、中序遍历的非递归实现

1、实现方法如下: 

在沿左子树搜索时,当搜索的节点不为空时,先进栈,在搜索左节点,不为空时继续入栈,继续以此规律搜索

当搜索的节点为空时,让一个节点出栈,并且访问该节点,然后搜索节点的右节点,再为空时再出栈一个节点并访问该节点,且继续搜索右子树

2、实现代码如下:

  1. //中序遍历非递归实现
  2. void inorder(bitree *t)
  3. {
  4. bitree *Stack[maxsize];
  5. int top = -1;
  6. bitree *p;
  7. if(t==NULL){
  8. printf("树为空\n");
  9. }
  10. p = t;
  11. while(p!=NULL||top!=-1){
  12. while(p!=NULL){
  13. if(top<maxsize-1){
  14. top++;
  15. Stack[top] = p;//入栈
  16. }else{
  17. printf("错误\n");
  18. }
  19. p = p->lchild;//指向左孩子
  20. }
  21. if(top==-1){
  22. printf("空\n");
  23. }else{
  24. p = Stack[top];//出栈
  25. printf("%c ",p->date);//访问节点的数据域
  26. top--;
  27. p = p->rchild;//指向右孩子
  28. }
  29. }
  30. }

1f2bce047ed645cabe4dd4d9626a9671.png

四、后序遍历的非递归实现  

 1、实现方法如下

在沿左子树搜索时,当搜索的节点不为空时,先进栈,在搜索左节点,不为空时继续入栈,继续以此规律搜索

当搜索的节点为空时,让一个节点出栈,节点标记为1,第一次出栈,节点不能访问,继续让该节点入栈,然后搜索节点的右节点,再为空时再出栈一个节点,且继续搜索右子树,

当节点第二次出栈时,该节点标记为2,此时访问该节点,第二次出栈,节点可以访问,然后搜索节点的右节点,再为空时再出栈一个节点,且继续搜索右子树

86f8acdb447a4232b48f51655facc683.jpeg

 该树的先序遍历结果为:ABDFGCE

_代表空格

在输入时应该输入成:AB_DF_ _G_ _C_E_ _

 2、实现代码如下

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #define MAX 100 // 栈中最后存储的结点数
  4. typedef char ElemType; // 为结点数据类型起别名
  5. typedef struct node // 二叉树中结点存储结构
  6. {
  7. ElemType data; // 存储结点数据
  8. struct node * lchild; // 指向结点左孩子指针
  9. struct node * rchild; // 指向结点右孩子指针
  10. }BSTree; //为二叉树中结点存储结构起别名
  11. typedef struct //二叉树结点顺序栈结构体定义
  12. {
  13. BSTree* data[MAX]; //数组存储二叉树各个结点
  14. int top; //用于指示栈顶
  15. }Stack; //二叉树顺序栈结构体类型的别名
  16. int flag[MAX]; //用于标识每个结点是第几次入栈
  17. //初始化顺序栈
  18. Stack * Init()
  19. {
  20. Stack * S;
  21. //为通讯录顺序栈分配内存
  22. S=(Stack *)malloc(sizeof(Stack ));
  23. if(S==NULL) //判断内存分配是否成功
  24. {
  25. printf("内存分配失败,结束程序\n");
  26. exit(0);
  27. }
  28. else
  29. {
  30. S->top=-1; //当栈为空时,顺序栈的栈顶位置设置为-1
  31. return S; //返回顺序栈的地址
  32. }
  33. }
  34. //顺序栈的入栈
  35. void Push(Stack *S, BSTree* x)
  36. {
  37. if(S->top<MAX) //判断顺序栈中是否已满
  38. {
  39. S->top ++; //将栈顶位置加1,为入栈元素做好准备
  40. //将入栈的元素的数据放置在栈顶位置
  41. S->data[S->top ]=x;
  42. }
  43. else
  44. printf("栈已满,无法入栈!\n");
  45. }
  46. //顺序栈出栈
  47. void Pop(Stack *S, BSTree **x)
  48. {
  49. if(S->top!=-1) //判断栈是否为空
  50. {
  51. //将栈顶元素的数据赋值给x指针所指向的变量
  52. (*x)=S->data[S->top];
  53. S->top--; //将栈顶位置减1
  54. }
  55. else
  56. printf("栈为空,无法出栈!\n");
  57. }
  58. //创建二叉树
  59. BSTree * Create()
  60. {
  61. ElemType ch;
  62. BSTree * root;
  63. scanf("%c",&ch); // 输入要创建二叉树的根结点数据
  64. if(ch==' ') // 判断二叉树是否为空的二叉树
  65. root=NULL; // 如果是空的二叉树则二叉树的根结点指针为空
  66. else // 如果不是则创建二叉树的根结点
  67. {
  68. //为二叉树的根结点分配存储空间
  69. root=(BSTree*)malloc(sizeof(BSTree));
  70. root->data=ch; // 将输入的数据存储在根结点的数据域中
  71. //通过递归调用创建根结点的左孩子结点,并使根结点左孩子指针指向该结点
  72. root->lchild=Create();
  73. //通过递归调用创建根结点的右孩子结点,并使根结点右孩子指针指向该结点
  74. root->rchild=Create();
  75. }
  76. return root;
  77. }
  78. //非递归后序遍历二叉树
  79. void Postorder(BSTree *root)
  80. {
  81. Stack *s1; //定义一个指向栈的指针
  82. s1=Init(); //初始化栈
  83. //判断二叉树是否遍历完了,当二叉树结点指针为空并且栈为空时表示
  84. //二叉树遍历完了
  85. while(root!=NULL || s1->top>-1)
  86. {
  87. if(root!=NULL) //当结点不为空时
  88. {
  89. Push(s1,root); // 将遍历中遇到的结点入栈
  90. flag[s1->top]=1; //标识该结点第1次入栈
  91. root=root->lchild; // 得到该结点的左孩子结点
  92. }
  93. else //当结点为空时,
  94. {
  95. Pop(s1,&root); //从栈中出栈得到一个结点
  96. if(flag[s1->top+1]==1)//判断出栈的结点是不是第1次入栈
  97. {
  98. Push(s1,root);//如果是第1次入栈则再次入栈
  99. flag[s1->top]=2; //标识该结点第2次入栈
  100. root=root->rchild; // 得到该结点的左孩子结点
  101. }
  102. //如果出栈的结点是2次入栈,则输出该结点数据,并设置指向结点指针为空
  103. else
  104. {
  105. printf("%3c",root->data); //输出结点数据
  106. root=NULL; // 设置指针为空
  107. }
  108. }
  109. }
  110. }
  111. int main()
  112. {
  113. BSTree *t;
  114. printf("输入要创建的树的根节点数据:\n");
  115. t =Create();
  116. printf("后序遍历非递归实现:");
  117. Postorder(t);
  118. printf("\n");
  119. return 0;
  120. }

 3、实现如下

b2e9a86629a24c358c6d7bfeaa6168bf.png


五、总结

无论是递归还是非递归遍历二叉树,由于每个节点仅被访问一次,则无论按哪一种次序进行遍历,对含n个节点的二叉树,其时间复杂性均为O(n)。所需辅助空间为遍历过程中栈的最大容量,即树的深度,最坏情况下为n,即空间复杂度也为O(n)。

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

闽ICP备14008679号