当前位置:   article > 正文

数据结构(六):二叉树的创建、递归遍历与非递归遍历、层次遍历_构建一棵二叉树,用递归和非递归算法对该二叉树进行先序、中序和后序遍历。

构建一棵二叉树,用递归和非递归算法对该二叉树进行先序、中序和后序遍历。

目录

一、二叉树的存储结构

二、创建一棵二叉树

三、二叉树的递归遍历

【先序遍历】

【中序遍历】

【后序遍历】

四、二叉树的非递归遍历

【中序遍历】

【先序遍历】

【后序遍历】

 五、二叉树的层次遍历


一、二叉树的存储结构

二叉树可采用顺序存储与链式存储,顺序存储的空间利用率较低,故一般采用链式存储。

链式存储结构描述如下:

  1. typedef struct BiTNode
  2. {
  3. ElemType data; //数据域
  4. struct BiTNode *lchild, *rchild; //左右孩子指针
  5. } BiTNode, *BiTree;

二、创建一棵二叉树

例如:输入二叉树的先序序列,即可得到一颗二叉树

例如:我们输入这颗二叉树的先序序列(空节点用0表示):1 2 0 4 6 0 0 0 3 0 5 0 0

然后我们输出任意几个结点的data数值,验证二叉树是否正确。

  1. #include<iostream>
  2. using namespace std;
  3. #define ElemType int
  4. typedef struct BiTNode
  5. {
  6. ElemType data;
  7. struct BiTNode *lchild, *rchild;
  8. } BiTNode, *BiTree;
  9. void createBiTree(BiTree& T)
  10. {
  11. ElemType d;
  12. cin >> d;
  13. if (d == 0)
  14. T = NULL;
  15. else
  16. {
  17. T = (BiTree)malloc(sizeof(BiTNode));
  18. T->data = d;
  19. createBiTree(T->lchild);
  20. createBiTree(T->rchild);
  21. }
  22. }
  23. int main()
  24. {
  25. BiTree root = NULL; //定义一棵空树
  26. cout << "请按先序序列输入各个结点(空节点用0表示):" << endl;
  27. createBiTree(root);
  28. //输出测试
  29. cout << "输出测试:" << endl;
  30. cout << root->lchild->data << endl;
  31. cout << root->lchild->rchild->lchild->data << endl;
  32. cout << root->rchild->rchild->data << endl;
  33. }

三、二叉树的递归遍历

先序遍历

  1. void PerOrder(BiTree T)
  2. {
  3. if(T!=NULL)
  4. {
  5. cout << T->data << " "; //visit(root);
  6. PerOrder(T->lchild);
  7. PerOrder(T->rchild);
  8. }
  9. }

中序遍历

  1. void InOrder(BiTree T)
  2. {
  3. if(T!=NULL)
  4. {
  5. InOrder(T->lchild);
  6. cout << T->data << " "; //visit(root);
  7. InOrder(T->rchild);
  8. }
  9. }

【后序遍历】

  1. void PostOrder(BiTree T)
  2. {
  3. if(T!=NULL)
  4. {
  5. PostOrder(T->lchild);
  6. PostOrder(T->rchild);
  7. cout << T->data << " "; //visit(root);
  8. }
  9. }

仍以前面的二叉树为例,输入结点创建二叉树后,对其进行先序、中序、后序遍历输出:

  1. #include<iostream>
  2. using namespace std;
  3. #define ElemType int
  4. typedef struct BiTNode
  5. {
  6. ElemType data;
  7. struct BiTNode *lchild, *rchild;
  8. } BiTNode, *BiTree;
  9. void createBiTree(BiTree& T)
  10. {
  11. ElemType d;
  12. cin >> d;
  13. if (d == 0)
  14. T = NULL;
  15. else
  16. {
  17. T = (BiTree)malloc(sizeof(BiTNode));
  18. T->data = d;
  19. createBiTree(T->lchild);
  20. createBiTree(T->rchild);
  21. }
  22. }
  23. void PerOrder(BiTree T)
  24. {
  25. if(T!=NULL)
  26. {
  27. cout << T->data << " "; //visit(root);
  28. PerOrder(T->lchild);
  29. PerOrder(T->rchild);
  30. }
  31. }
  32. void InOrder(BiTree T)
  33. {
  34. if(T!=NULL)
  35. {
  36. InOrder(T->lchild);
  37. cout << T->data << " "; //visit(root);
  38. InOrder(T->rchild);
  39. }
  40. }
  41. void PostOrder(BiTree T)
  42. {
  43. if(T!=NULL)
  44. {
  45. PostOrder(T->lchild);
  46. PostOrder(T->rchild);
  47. cout << T->data << " "; //visit(root);
  48. }
  49. }
  50. int main()
  51. {
  52. BiTree root = NULL; //定义一棵空树
  53. cout << "请按先序序列输入各个结点(空节点用0表示):" << endl;
  54. createBiTree(root);
  55. //递归遍历
  56. cout << "先序遍历结果为:";
  57. PerOrder(root);
  58. cout << endl;
  59. cout << "中序遍历结果为:";
  60. InOrder(root);
  61. cout << endl;
  62. cout << "后序遍历结果为:";
  63. PostOrder(root);
  64. cout << endl;
  65. }

注意:递归遍历的特点是:

①每个节点都访问一次且仅访问一次;

②递归遍历中,递归工作栈的深度恰好为树的深度

四、二叉树的非递归遍历

【中序遍历】

以此棵二叉树为例:

我们借助栈来分析中序遍历(非递归)的访问过程:

  1. 沿着根的左孩子,依次入栈,直到左孩子为空。
    说明已经找到可以输出的结点,此时栈内元素依次为 A,B,D
  2. 栈顶元素出栈并访问:若其右孩子为空,继续执行 (步骤2) ,若其右孩子不空,将右子树转执行 (步骤1).
    栈顶D出栈并访问,它是中序序列的第一个结点;D右孩子为空,栈顶B出栈并访问;B右孩子不空,将其右孩子E入栈,E左孩子为空,栈顶E出栈并访问;E右孩子为空,栈顶A出栈并访问;A右孩子不空,将其右孩子C入栈,C左孩子为空,栈顶C出栈并访问。
    所以,中序序列为:D B E A C

【先序遍历】

        先序遍历与中序遍历基本思想类似,只需把访问结点操作放在入栈操作前面即可,具体参考下面的代码。

【后序遍历】

        后续遍历的非递归实现是三种遍历中最难的,具体思路为:

  1. 沿着根的左孩子,依次入栈,直到左孩子为空。
    此时栈内元素为A B D
  2. 读栈顶元素:若其右孩子不空且未被访问过,将右子树执行 (步骤1);否则,栈顶元素出栈并访问。
    栈顶D的右孩子为空,出栈并访问,他是后序序列的第一个结点;栈顶B的右孩子不空且未被访问过,E入栈,栈顶E的左右孩子均为空,出栈并访问;栈顶B的右孩子不空但已被访问,B出栈并访问;栈顶A的右孩子不空且未被访问过,C入栈,栈顶C的左右孩子均为空,出栈并访问;栈顶A的右孩子不空但已被访问,A出栈并访问。
    由此,后序序列为:D E B C A

代码

  1. #include<iostream>
  2. #include <stack>
  3. using namespace std;
  4. #define ElemType int
  5. typedef struct BiTNode
  6. {
  7. ElemType data;
  8. struct BiTNode *lchild, *rchild;
  9. } BiTNode, *BiTree;
  10. void createBiTree(BiTree& T)
  11. {
  12. ElemType d;
  13. cin >> d;
  14. if (d == 0)
  15. T = NULL;
  16. else
  17. {
  18. T = (BiTree)malloc(sizeof(BiTNode));
  19. T->data = d;
  20. createBiTree(T->lchild);
  21. createBiTree(T->rchild);
  22. }
  23. }
  24. //先序遍历
  25. void PerOrder2(BiTree T)
  26. {
  27. stack<BiTree> S;
  28. BiTree p = T;
  29. while (p || !S.empty())
  30. {
  31. if (p)
  32. {
  33. cout << p->data << " "; //visit(p);
  34. S.push(p);
  35. p = p->lchild;
  36. }
  37. else
  38. {
  39. p = S.top();
  40. S.pop();
  41. p = p->rchild;
  42. }
  43. }
  44. }
  45. //中序遍历
  46. void InOrder2(BiTree T)
  47. {
  48. stack<BiTree> S; // #include<stack>
  49. BiTree p = T; //p是遍历指针
  50. while (p || !S.empty())
  51. {
  52. if (p)
  53. {
  54. S.push(p);
  55. p = p->lchild;
  56. }
  57. else
  58. {
  59. p = S.top();
  60. S.pop(); //栈顶元素出栈
  61. cout << p->data << " "; //visit(p);
  62. p = p->rchild; //转向出栈结点的右子树
  63. }
  64. }
  65. }
  66. //后序遍历
  67. void PostOrder2(BiTree T)
  68. {
  69. stack<BiTree> S;
  70. BiTree p = T, r = NULL; //r是辅助指针,指向最近访问过的结点
  71. while (p || !S.empty())
  72. {
  73. if (p)
  74. {
  75. S.push(p);
  76. p = p->lchild;
  77. }
  78. else
  79. {
  80. p = S.top();
  81. if (p->rchild && p->rchild != r) //若右子树存在,且未被访问过
  82. p = p->rchild;
  83. else
  84. {
  85. S.pop();
  86. cout << p->data << " "; //visit(p);
  87. r = p; //记录最近访问过的结点
  88. p = NULL; //结点访问完后,重置p指针
  89. }
  90. }
  91. }
  92. }
  93. int main()
  94. {
  95. BiTree root = NULL; //定义一棵空树
  96. cout << "请按先序序列输入各个结点(空节点用0表示):" << endl;
  97. createBiTree(root);
  98. //非递归遍历
  99. cout << "先序遍历(非递归)结果为:";
  100. PerOrder2(root);
  101. cout << endl;
  102. cout << "中序遍历(非递归)结果为:";
  103. InOrder2(root);
  104. cout << endl;
  105. cout << "后序遍历(非递归)结果为:";
  106. PostOrder2(root);
  107. cout << endl;
  108. }

 五、二叉树的层次遍历

        要进行层次遍历,需要借助一个队列。先将二叉树根结点入队,然后出队,访问出队结点,若它有左子树,则将左子树根结点入队;若它有右子树,则将右子树根结点入队。然后出队,访问出队结点……如此反复,直至队列为空。

  1. void LevelOrder(BiTree T)
  2. {
  3. queue<BiTree> Q; //#include<queue>
  4. BiTree p;
  5. Q.push(T); //将根节点入队
  6. while (!Q.empty()) //队列不空则循环
  7. {
  8. p = Q.front();
  9. Q.pop(); //队头结点出队
  10. cout << p->data << " "; //visit(p);
  11. if (p->lchild != NULL)
  12. Q.push(p->lchild);
  13. if (p->rchild != NULL)
  14. Q.push(p->rchild);
  15. }
  16. }

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

闽ICP备14008679号