后序遍历的非递归算法
二叉树后序遍历的递归和非递归算法

安 徽电气工 程 职 业 技术学 院学报
:薹6 M2 a r 0 c h 0
.
-X树后序遍历的递归和非递归算法
孙泽宇, 赵国增 , 舒云星・
( 洛阳工业高等专科学校计算机系 , 河南 洛阳 4 10 ) 703
[ 要 ] 论述了二又树后序遍历的递归算法和非递归算法, 摘 对递归算法中的工作栈 的执行过程做 了
Srcbt e t t ie { u r
● 收稿 日期 :0 5—1 0 70 . 2— 2
作者筒介: 孙泽字(97 . 吉林长春人. 17 一) 男。 洛阳工业高等专科学校计算机秉麓师。研究方向: 人工智能。 趟 目增 (97 . 河南越壁人 。 阳工业高等专科 学校计算机 秉麓师 。研究方 向: 1 一) 男。 7 洛 人工智能。
s c br 木e , r h;} t t ie lt 木 i t m te f g
后序遍历二叉树的递归算法如下 :
T p d fs u tBT o e y e e r c in d t
法及执行时栈 的变化情况 , 可设计 出较好 的非递归化算法 , 本文讨论了二叉树后序遍历的递归和非递归
算法。 2 后序遍历二叉树的递归算法
1 后序遍历左子树( ) 若左子树不为空 ) 2 后序遍历右子树( ) 若右子树不为空 ) 3 访问根结点 ( ) 若存在根结点)
二叉树数据结构如下 :
二叉树是数据结构 中最常见 的存储形式 , 在算法与数据结构中经常使用。树与森林都可以转换为 二叉树 , 而遍历算法则是二叉树最重要的操作 。所谓遍历二叉树 , 就是遵从某种次序 , 遍访二叉树 中的
所有结点, 使得每个结点被访问一次 , 而且仅一次。在遍历算法中, 递归算法是最普遍 的, 弄清 了递归算
后序遍历的非递归算法(C详细)

后序遍历的非递归算法(C详细)后序遍历是二叉树遍历的一种方式,它的顺序是先遍历左子树,然后遍历右子树,最后访问根节点。
非递归实现后序遍历的算法可以使用栈来辅助实现。
首先,我们需要定义一个树节点的数据结构,例如:```cstruct TreeNodeint val;struct TreeNode* left;struct TreeNode* right;};```接下来,我们使用一个辅助栈来进行非递归后序遍历。
首先需要创建一个空栈,并将根节点入栈。
然后开始循环,直到栈为空为止。
在循环中,首先取出栈顶节点,如果该节点没有左子树且没有右子树,说明该节点是叶子节点,可以直接输出该节点的值。
如果该节点有左子树或者右子树,需要判断是否已经遍历过该节点的子节点。
为了实现后序遍历的顺序,我们需要一个标记变量来记录上次访问的节点。
如果上次访问的节点是该节点的右子树,说明该节点的左右子节点都已经访问过了,可以直接输出该节点的值。
反之,如果上次访问的节点不是该节点的右子树,将该节点重新入栈,并以右、左、中的顺序将其右子树、左子树入栈。
下面给出完整的代码实现:```c#include <stdio.h>#include <stdlib.h>struct TreeNodeint val;struct TreeNode* left;struct TreeNode* right;};void postOrderTraversal(struct TreeNode* root)if (root == NULL)return;}struct TreeNode* lastVisited = NULL; // 上次访问的节点struct TreeNode* node = root; // 当前遍历的节点struct TreeNode* stack[100]; // 栈int top = -1; // 栈顶指针while (node != NULL , top != -1)if (node != NULL)stack[++top] = node; // 入栈node = node->left; // 访问左子树} elsestruct TreeNode* temp = stack[top]; // 取出栈顶节点if (temp->right == NULL , temp->right == lastVisited) printf("%d ", temp->val);top--; // 出栈lastVisited = temp; // 记录上次访问的节点} elsenode = temp->right; // 访问右子树}}}struct TreeNode* createNode(int val)struct TreeNode* node = (structTreeNode*)malloc(sizeof(struct TreeNode));if (node != NULL)node->val = val;node->left = NULL;node->right = NULL;}return node;int mai//创建一个二叉树struct TreeNode* root = createNode(1); root->left = createNode(2);root->right = createNode(3);root->left->left = createNode(4);root->left->right = createNode(5); root->right->left = createNode(6); root->right->right = createNode(7);//后序遍历二叉树printf("后序遍历结果:"); postOrderTraversal(root);printf("\n");return 0;```以上代码中,我们使用了一个辅助数组作为栈来实现非递归遍历。
二叉树遍历算法——包含递归前、中、后序和层次,非递归前、中、后序和层次遍历共八种

⼆叉树遍历算法——包含递归前、中、后序和层次,⾮递归前、中、后序和层次遍历共⼋种⾸先,要感谢⽹上的参考资料。
1. /876134/1178079(作者:BlackAlpha)2. /fzh1900/article/details/14056735(作者:_云淡风轻)3. /stpeace/article/details/8138458(作者:stpeace)⼆叉树是使⽤的⽐较⼴泛的⼀种数据结构,这⾥我写了⼆叉树的相关操作,包括初始化、新建、以及遍历。
这⾥主要是为了学习⼆叉树的遍历算法,我总结后,写了⼋种⼆叉树的遍历算法,分别是:1.递归先序遍历2.递归中序遍历3.递归后序遍历4.⾮递归先序遍历(单栈辅助)5.⾮递归中序遍历(单栈辅助)6.⾮递归后序遍历(单栈辅助)7.递归层次遍历8.⾮递归层次遍历(队列辅助)当然,这⾥还要⽤到栈和队列,博客中以前有提到过(链式的栈和链式队列),其实还可以⽤顺序栈和顺序队列的(博客中后⾯将补上这块)。
下⾯直接上代码:LinkStack.h 链式栈头⽂件[cpp]1. #ifndef _LINK_STACK_H_H2. #define _LINK_STACK_H_H3.4. #include "BiTree.h"5.6. typedef pBiTree LStackEle;7.8. typedef struct LSNODE9. {10. LStackEle ele;11. struct LSNODE *pnext;12. }LSNode, *pLSNode;13.14. typedef struct LSTACK15. {16. pLSNode top;17. }LStack, *pLStack;18.19. //栈初始化20. void InitLinkStack(LStack &s);21.22. //⼊栈23. void PushLinkStack(LStack &s, LStackEle ele);24.26. void PopLinkStack(LStack &s, LStackEle &ele);27.28. //判断栈是否为空29. bool IsemptyLinkStack(LStack s);30.31. //获得栈顶值32. LStackEle GetTopLinkStack(LStack s);33.34. #endifLinkQueue.h 链式队列头⽂件[html]1. #ifndef _LINK_QUEUE_H_H2. #define _LINK_QUEUE_H_H3.4. #include "BiTree.h"5.6. typedef pBiTree LQueueEle;7.8. typedef struct LQNODE9. {10. LQueueEle ele;11. struct LQNODE *pnext;12. }LQNode, *pLQNode;13.14. typedef struct LQUEUE15. {16. pLQNode rear;17. pLQNode front;18. }LQueue, *pLQueue;19.20. //初始化队列21. void InitLinkQueue(LQueue &q);22.23. //⼊队24. void EnLinkQueue(LQueue &q, LQueueEle ele);25.26. //出队27. void DeLinkQueue(LQueue &q, LQueueEle &ele);28.29. //判断队列是否为空30. bool IsemptyLinkQueue(LQueue q);31.32. //获得队头元素值33. LQueueEle GetFrontLinkQueue(LQueue q);34.35. #endifBiTree.h ⼆叉树头⽂件[cpp]1. #ifndef _BITREE_H_H2. #define _BITREE_H_H3.4. typedef struct BINODE5. {7. struct BINODE *plchild;8. struct BINODE *prchild;9. }BiNode, *pBiTree;10.11. //初始化⼆叉树(含根节点)12. void InitBiTree(pBiTree &bt, int ele);13.14. //创建⼆叉树节点15. BiNode *CreateBiTreeNode(pBiTree lchild, pBiTree rchild, int ele);16.17. //插⼊左⼦⼆叉树18. void InsertLChild(pBiTree parent, pBiTree lchild);19.20. //插⼊右⼦⼆叉树21. void InsertRChild(pBiTree parent, pBiTree rchild);22.23. //计算⼆叉树的深度24. int DeepBiTree(pBiTree bt);25.26. //递归先序遍历27. void RePreOrderTraverse(pBiTree bt);28.29. //递归中序遍历30. void ReInOrderTraverse(pBiTree bt);31.32. //递归后序遍历33. void RePostOrderTraverse(pBiTree bt);34.35. //⾮递归先序遍历⼆36. void NonRePreOrderTraverse(pBiTree bt);37.38. //⾮递归中序遍历39. void NonReInOrderTraverse(pBiTree bt);40.41. //⾮递归后序遍历42. void NonRePostOrderTraverse(pBiTree bt);43.44. //⾮递归层次遍历45. void NonReLevelOrderTraverse(pBiTree bt);46.47. //递归层次遍历48. void ReLevelOrderTraverse(pBiTree bt);49.50. void PrintLevelNode(pBiTree bt, int level);51.52. #endifLinkStack.cpp 链式栈源⽂件[html]1. #include "LinkStack.h"2. #include <stdlib.h>3. #include <stdio.h>4.5. //栈初始化6. void InitLinkStack(LStack &s)7. {8. s.top= NULL;9. }10.11. //⼊栈12. void PushLinkStack(LStack &s, LStackEle ele)13. {14. pLSNode pnew = (pLSNode)malloc(sizeof(LSNode));15. if (pnew == NULL)16. {17. printf("内存分配失败!\n");18. exit(EXIT_FAILURE);19. }20.21. pnew->ele = ele;22. pnew->pnext = s.top;23. s.top = pnew;24. }25.26. //出栈27. void PopLinkStack(LStack &s, LStackEle &ele)28. {29. pLSNode pt = NULL;30. if (IsemptyLinkStack(s))31. {32. printf("栈为空,不能出栈操作!\n");33. exit(EXIT_FAILURE);34. }35. else36. {37. ele = s.top->ele;38. pt = s.top;39. s.top = pt->pnext;40. free(pt);41. pt = NULL;42. }43.44. }45.46. //判断栈是否为空47. bool IsemptyLinkStack(LStack s)48. {49. if (s.top == NULL)50. return true;51. else52. return false;53. }54.55. //获得栈顶元素56. LStackEle GetTop(LStack s)57. {58. if (IsemptyLinkStack(s))59. {60. printf("栈为空,不能获得栈顶元素值!\n");61. exit(EXIT_FAILURE);62. }63. else64. return s.top->ele;65. }LinkQueue.cpp 链式队列源⽂件[cpp]1. #include <stdlib.h>2. #include <stdio.h>3. #include "LinkQueue.h"4.5. //初始化队列6. void InitLinkQueue(LQueue &q)7. {8. q.front = (pLQNode)malloc(sizeof(LQNode));9. if (q.front == NULL)10. {11. printf("内存分配失败!\n");12. exit(EXIT_FAILURE);13. }14.15. q.rear = q.front;16. }17.18. //⼊队19. void EnLinkQueue(LQueue &q, LQueueEle ele)20. {21. pLQNode pnew = (pLQNode)malloc(sizeof(LQNODE));22. if (pnew == NULL)23. {24. printf("内存分配失败!\n");25. exit(EXIT_FAILURE);26. }27.28. pnew->ele = ele;29. pnew->pnext = NULL;30. q.rear->pnext = pnew;31. q.rear = pnew;32. }33.34. //出队35. void DeLinkQueue(LQueue &q, LQueueEle &ele)36. {37. pLQNode pt = NULL;38.39. if (IsemptyLinkQueue(q))40. {41. printf("队列为空,不能出队操作!\n");42. exit(EXIT_FAILURE);43. }44.45. ele = q.front->pnext->ele;46. pt = q.front->pnext;47. q.front->pnext = pt->pnext;48. free(pt);49. /*50. pt是最后⼀个节点时,释放完了以后,尾指针指向的51. 是随机内存,所以让它和头指针指向同⼀个地址。
树的后序遍历非递归-双栈法

树的后序遍历⾮递归-双栈法因为我们可以⽤栈实现前序遍历,所以我们同样可以实现中,右,左的遍历然后我们每次遍历到了节点不去输出⽽是添加到另⼀个栈st2中,最后将st2中的元素⼀个个的弹出就得到了后序遍历左,右,中。
参考博客:附上代码:/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/class Solution {public:vector<int> postorderTraversal(TreeNode* root) {stack<TreeNode*> st1;vector<int> res;if(!root)return res;//⼀个栈⽤于中,右,左遍历//另⼀个⽤于逆序,我这⾥直接使⽤⼀个vector,然后将其逆序,和栈是同样的作⽤st1.push(root);while(!st1.empty()){TreeNode *cur = st1.top();res.push_back(cur->val);st1.pop(); //这⾥先将左⼦树⼊栈,与前序遍历相反if(cur->left)st1.push(cur->left); //然后将右⼦树⼊栈if(cur->right)st1.push(cur->right);}int i = 0;int j = res.size()-1;while(i < j){int temp = res[i];res[i] = res[j];res[j] = temp;i++;j--;}return res;}};。
二叉树的遍历

二叉树的遍历算法1 先序遍历(T、p、S()、top)\*先序遍历的非递归算法,T为根指针,p为指针,指向当前结点。
使用一个栈S()、top为栈顶指针*\1.if(T=NULL)2.Printf( “这是一棵空二叉树”);3.else{△△p=T;top=0;4. While(top≠0)||(p≠NULL){△while(p≠NULL){﹡Visit(p→data); \﹡访问结点﹡\top=top+1;if (top>n) 调用栈满else{S(top)=p→rchild;P=P→lchild;}}﹡if (top≠0){p= S(top);top--;}}△}△△{算法结束}算法2 中序遍历(T、p、S()、top)\*{中序遍历的非递归算法,使用栈S(),top为栈顶指针,T指向根,p为指针,指向当前结点*\top=0,p=TWhile(top≠0)||(P≠NULL){While(P≠NULL){Top=top+1if (top>n) 调用栈满else{S(top)=p, p=p→lchied;}}If (top≠null){p=S(top);top=top-1;Visit(p→data); \﹡访问结点﹡\p=p→rchild;}}{算法结束}算法3 后序遍历(T、p、S()、top)\*后序遍历的非递归算法,T指向根,P为指标指向当前结点,使用堆栈S(),栈顶指针为top,*\1、if (t=NIL)2、then { 输出“这是一棵空树”go 22 \* 结束 *\3、else { p=t;top=0;4、 while (top≠0)||(p≠NIL) {5、 while (p≠NIL){6、 top=top+1;7、 if (top﹥n)8、调用栈满9、 else{S(top)=p;10、 p=p→lchild;}11、 }12、 if (top≠0){13、 p=S(top);top=top-114、 if (p﹤0){15、 p=-p;16、 Visit(p→data); \﹡访问结点﹡\17、 p=NIL;〕18、 else {top=top+1;19、 S(top)=-P;20、 p=p→rchild;}21、 }22、{算法结束}算法4 二叉树后序遍历(t、p、S()、top、h)\*后序遍历的非递归算法,T指向根,使用堆栈S(),top为栈顶指针,P为指针,指向当前结点,h为指针,指向刚被访问结点*\1、if (T=Nil){ 输出“这是一棵空树”go 20}2、else{﹡p=t,top=03、 if (p→lchild=Nil)&&(P→rchild=Nil)4、 then go 125、 else{△△top=top+1;S(top)=p;6、 if (p→lchild=Nil)7、 {p= p→rchild; go 3;}8、 else {△if (p→rchild=Nil)9、 go 1110、 else {top=top+1; S(top)= p→rchild;}11、 P=p→lchil; go 3}△}△△12、 Visit(p→data); \﹡访问结点﹡\13、 h=p14、 if (top=0){15、输出“栈空” go 20;}16、 else {p= S(top);top=top-1;17、 if(p→Lchild=h)OR(p→rchild=h)18、 then go 12;19、 else go 3;}}﹡20、{算法结束}。
后序遍历的非递归实现方式。

后序遍历的非递归实现方式。
那后序遍历又是啥呀?这就好比我们要按照一种特别的顺序去参观这棵树。
后序遍历的顺序是先访问左子树,再访问右子树,最后才访问根节点。
就好像我们先沿着左边的小路把左边的风景都看完,再沿着右边的小路看右边的风景,最后才站在树的中心位置好好欣赏整个画面。
那非递归实现方式又是怎么一回事呢?咱们先讲讲递归。
递归就像是爬楼梯,一步一步按照同样的方法往上走。
比如说,你要计算1 + 2 + 3 + 4 + 5 ,你可以这样想:5加上前面1到4的和,那1到4的和又可以看成4加上前面1到3的和,就这样一步一步算下去,这就是递归。
可是非递归呢,就像是换了一种走法,不一直重复同样的步子啦。
对于二叉树后序遍历的非递归实现,我们可以借助一个“小助手”,这个小助手就是栈。
栈就像一个装东西的小盒子,不过它有个特别的规矩,就是先进去的东西后出来,后进去的东西先出来,就像我们往一个竹筒里放弹珠,先放进去的在下面,要拿的时候得先把上面的拿出来。
下面咱们来看一个简单的例子哈。
假设有一棵二叉树,根节点是1 ,它的左子节点是2 ,右子节点是3 。
2的左子节点是4 ,右子节点是5 。
那按照后序遍历的顺序,应该是先看4 ,再看5 ,然后看2 ,接着看3 ,最后看1 。
用非递归的方法怎么实现呢?咱们先把根节点1放到栈里,就像把1号宝贝放到小盒子里。
然后看看它有没有右子节点,有啊,是3 ,那就把3也放到栈里。
再看看有没有左子节点,有,是2 ,也放到栈里。
这时候栈里就有1 、3 、2啦。
接下来,我们从栈里拿出最上面的,也就是2 。
看看2有没有右子节点,有,是5 ,放到栈里,再看看有没有左子节点,有,是4 ,也放到栈里。
现在栈里就是1 、3 、5 、4啦。
然后拿出最上面的4 ,4没有子节点啦,那4就是我们第一个要访问的节点。
接着拿出5 ,5也没有子节点了,5就是第二个要访问的节点。
再拿出2 ,2的左右子节点都访问过啦,所以2就是第三个要访问的节点。
实习

/download/a071800/3758620本贴给出二叉树先序、中序、后序三种遍历的非递归算法,此三个算法可视为标准算法。
1.先序遍历非递归算法#define maxsize 100typedef struct{Bitree Elem[maxsize];int top;}SqStack;void PreOrderUnrec(Bitree t){SqStack s;StackInit(s);p=t;while (p!=null || !StackEmpty(s)){while (p!=null) //遍历左子树{visite(p->data);push(s,p);p=p->lchild;}//endwhileif (!StackEmpty(s)) //通过下一次循环中的内嵌while实现右子树遍历{p=pop(s);p=p->rchild;}//endif}//endwhile}//PreOrderUnrec2.中序遍历非递归算法#define maxsize 100typedef struct{Bitree Elem[maxsize];int top;}SqStack;void InOrderUnrec(Bitree t){SqStack s;StackInit(s);p=t;while (p!=null || !StackEmpty(s)){while (p!=null) //遍历左子树{push(s,p);p=p->lchild;}//endwhileif (!StackEmpty(s)){p=pop(s);visite(p->data); //访问根结点p=p->rchild; //通过下一次循环实现右子树遍历}//endif}//endwhile}//InOrderUnrec3.后序遍历非递归算法#define maxsize 100typedef enum{L,R} tagtype;typedef struct{Bitree ptr;tagtype tag;}stacknode;typedef struct{stacknode Elem[maxsize];int top;}SqStack;void PostOrderUnrec(Bitree t){SqStack s;stacknode x;StackInit(s);p=t;do{while (p!=null) //遍历左子树{x.ptr = p;x.tag = L; //标记为左子树push(s,x);p=p->lchild;}while (!StackEmpty(s) && s.Elem[s.top].tag==R){x = pop(s);p = x.ptr;visite(p->data); //tag为R,表示右子树访问完毕,故访问根结点}if (!StackEmpty(s)){s.Elem[s.top].tag =R; //遍历右子树p=s.Elem[s.top].ptr->rchild;}}while (!StackEmpty(s));}//PostOrderUnrec遍历二叉树的递归程序:void Traverse(BiTree T){if(T){//visit,先序遍历Traverse(T->lchild);//visit,中序遍历Traverse(T->rchild);//visit,后序遍历}}可以看到三种遍历方法的递归实现形式完全一样,只需改变visit的位置,就得到不同遍历序列。
后序遍历非递归算法

后序遍历非递归算法后序遍历是二叉树遍历中的一种,它的遍历顺序是先访问左子树、再访问右子树、最后访问根节点。
在非递归算法中,我们需要借助栈来实现后序遍历。
具体步骤如下:1. 新建一个栈,并将根节点入栈2. 定义两个节点变量pre和cur,初始化pre为null3. 当栈不为空时,循环执行以下操作:- 将栈顶元素cur赋值为栈顶元素,但不弹出该元素- 如果当前节点没有左右子节点,或者左右子节点已经被访问过了,那么弹出当前节点,并将其值打印输出,并将pre赋值为当前节点- 否则,若当前节点有右子节点,就将其右子节点入栈。
若当前节点有左子节点,则将其左子节点入栈4. 循环结束可以看到,后序遍历的算法和前序遍历、中序遍历都有所区别。
与前序遍历的主要区别在于,在访问节点前,需要判断该节点的左右子节点是否已经被访问过。
而与中序遍历的主要区别在于,在访问节点后,需要将该节点的值打印输出。
此外,后序遍历还需要维护一个pre节点变量,用于记录上一个被访问过的节点。
那么,后序遍历的非递归算法有什么优点呢?相比递归算法,它的空间复杂度更低,因为递归算法需要维护函数调用栈。
而非递归算法中使用的栈只需要在遍历过程中存储节点,不需要再维护函数调用栈。
此外,非递归算法在一些嵌入式系统、服务器等资源受限的环境下表现更优秀。
总体而言,后序遍历非递归算法是一种非常实用的二叉树遍历算法,它可以帮助我们更加高效地对二叉树进行遍历,尤其是在空间限制较大的情况下。
需要注意的是,该算法的具体实现过程可能会因为树结构的复杂性而略有差异,建议大家在编写代码时用心梳理整个算法过程。
二叉树的遍历及相关题目

⼆叉树的遍历及相关题⽬⼆叉树的遍历及相关题⽬1.1⼆叉树遍历的概念⼆叉树结构体的定义:typedef struct node{ ElemType data; struct node * lchild; struct node * rchild;}⼆叉树的遍历是指按照⼀定的次序访问⼆叉树中的所有的节点,并且每个节点仅访问⼀次的过程。
若规定先遍历左⼦树,后遍历右⼦树,则对于⾮空⼆叉树,可得到如下3种递归的遍历⽅法:(1)先序遍历访问根节点,先序遍历左⼦树,先序遍历右⼦树。
(根,左,右)(2)中序遍历中序遍历左⼦树,访问根节点,中序遍历右⼦树。
(左,根,右)(3)后序遍历后序遍历左⼦树,后序遍历右⼦树,访问根节点。
(左,右,根)除此之外也有层次遍历。
先访问根节点,在从左到右访问第⼆层的所有节点,从左到右访问第三层的所有节点......1.2⼆叉树遍历递归算法先序遍历递归算法:void PreOrder(BTNode * b){ if(n != NULL) { cout<<b->data; PreOrder(b->lchild); PreOrder(b->rchild); }}中序遍历递归算法void InOrder(BTNode * b){ if(n != NULL) { InOrder(b->lchild); cout<<b->data; InOrder(b->rchild); }}后序遍历递归算法:void PostOrder(BTNode * b){ if(b != NULL) { PostOrder(b->lchild); PostOrder(b->rchild); cout<<b->data; }}题⽬1:输出⼀个给定⼆叉树的所有的叶⼦节点:void DispLeaf(BTNode * b){ if(b != NULL) { if(b->lchild == NULL && b->rchild == NULL) cout<<b->data; DispLeaf(b->lchild); DispLeaf(b->rchild); }}以上算法采⽤先序遍历输出了所有的叶⼦节点,所以叶⼦节点是从左到右输出的。
二叉树的递归及非递归的遍历及其应用

二叉树的递归及非递归的遍历及其应用二叉树是一种常见的数据结构,由节点和边组成,每个节点最多有两个子节点,分别称为左子节点和右子节点。
递归和非递归是两种遍历二叉树的方法,递归是通过递归函数实现,而非递归则利用栈的数据结构来实现。
二叉树的遍历是指按照一定的顺序访问二叉树中的每个节点。
常见的遍历方式有前序遍历、中序遍历和后序遍历。
1.前序遍历(Preorder Traversal):在前序遍历中,首先访问根节点,然后递归地遍历左子树和右子树。
遍历顺序为:根节点-左子树-右子树。
2.中序遍历(Inorder Traversal):在中序遍历中,首先递归地遍历左子树,然后访问根节点,最后递归地遍历右子树。
遍历顺序为:左子树-根节点-右子树。
3.后序遍历(Postorder Traversal):在后序遍历中,首先递归地遍历左子树和右子树,最后访问根节点。
遍历顺序为:左子树-右子树-根节点。
递归遍历方法的实现相对简单,但可能存在性能问题,因为递归调用会导致函数的调用和返回开销,尤其是在处理大规模二叉树时。
而非递归遍历方法则能够通过利用栈的特性,在迭代过程中模拟函数调用栈,避免了函数调用的性能开销。
非递归遍历二叉树的方法通常利用栈来实现。
遍历过程中,将节点按照遍历顺序入栈,然后访问栈顶元素,并将其出栈。
对于前序遍历和中序遍历,入栈顺序不同,而对于后序遍历,需要维护一个已访问标记来标识节点是否已访问过。
以下是非递归遍历二叉树的示例代码(以前序遍历为例):```pythonclass TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = rightdef preorderTraversal(root): if not root:return []stack = []result = []stack.append(root)while stack:node = stack.pop()result.append(node.val)if node.right:stack.append(node.right)if node.left:stack.append(node.left)return result```在实际应用中,二叉树的遍历方法有很多应用。
树的后序遍历非递归算法

树的后序遍历非递归算法
树的后序遍历是一种常用的算法,它可以让我们遍历树结构的所有
节点,并按照一定的顺序进行处理。
而非递归算法则是解决树的遍历
问题的一种常用方法。
下面就为大家介绍一下树的后序遍历的非递归算法:
1. 首先我们需要创建一个堆栈,用于保存遍历过程中的节点。
同时,
我们需要定义一个指针指向当前操作的节点,初始值为根节点。
2. 然后我们开始遍历树,先将根节点入栈。
接下来进入一个循环:
3. 在循环中,我们将指针向左移动,直到遇到一个没有左子节点的节
点为止。
在这个移动的过程中,我们需要将每个遍历过的节点都入栈。
4. 如果当前节点没有右子节点,或者当前节点的右子节点已经入栈,
那么就可以对当前节点进行操作(例如打印出当前节点的值,或者将
其从堆栈中弹出),并将指针指向堆栈中的下一个节点。
5. 如果当前节点存在右子节点,并且其右子节点还没有入栈,则将其
右子节点入栈。
6. 重复步骤3~5,直到堆栈为空为止。
这就完成了一次树的后序遍历。
通过上述非递归算法,我们可以很容易地遍历整棵树,并进行各种自定义操作。
同时,由于使用了堆栈的存储方式,算法复杂度相比递归算法也有了一定程度的优化。
树的三种遍历方式

树的三种遍历方式树是一种非常重要的数据结构,它在计算机科学中应用广泛。
树可以用于搜索、排序、数据表、文件系统等诸多领域。
而树的遍历方式,则是在树中搜索数据的一种方法。
树的遍历方式有三种,分别是前序遍历、中序遍历和后序遍历。
这三种遍历方式在树的数据结构中有着重要的作用,它们可以用来检索所有节点的信息。
下面我们将对它们一一进行介绍。
1.前序遍历前序遍历也称为先序遍历,它的顺序是根节点->左子树->右子树。
它的算法描述如下:前序遍历的递归算法实现:void PreOrderTraversal(TraversalNode T){ if (T) { visit(T); PreOrderTraversal(T->left); PreOrderTraversal(T->right); } }前序遍历的非递归算法实现:void PreOrderTraversal(TraversalNode T){ while (T || !StackIsEmpty(S)) { while (T) { visit(T); push(Stack,T); T = T->left; } if(!StackIsEmpty(S)) { T = pop(Stack);T = T->right; } } }2.中序遍历中序遍历的顺序是左子树->根节点->右子树。
它的算法描述如下:中序遍历的递归算法实现:void InOrderTraversal(TraversalNode T) { if(T) { InOrderTraversal(T->left);visit(T);InOrderTraversal(T->right); } }中序遍历的非递归算法实现:void InOrderTraversal(TraversalNode T){ while (T || !StackIsEmpty(S)) { while(T) { push(Stack, T); T =T->left; } if (!StackIsEmpty(S)){ T = pop(Stack); visit(T); T = T->right; } } }3.后序遍历后序遍历的顺序是左子树->右子树->根节点。
非递归后序遍历求带权路径长度

非递归后序遍历求带权路径长度1.引言在计算机科学和算法领域中,树是一种常见的数据结构,而树的遍历是对树中所有节点进行访问的一种重要操作。
后序遍历是一种常见的树遍历方式,它的应用场景非常广泛。
今天我们将着重讨论非递归后序遍历,并探讨如何利用非递归后序遍历来求解树中带权路径长度的问题。
2.非递归后序遍历非递归后序遍历是指在遍历树的过程中,不使用递归的方式来实现后序遍历的操作。
它通常借助栈来实现。
我们可以通过模拟递归的过程,在栈的帮助下,实现非递归后序遍历。
这种方式能够有效地降低递归带来的空间开销,提高算法的效率。
3.树的带权路径长度树的带权路径长度是指树中所有节点的路径长度之和。
路径长度是指从根节点到叶子节点的路径上边的权值之和。
带权路径长度可以用来衡量树的结构以及节点之间的关系,它在树的相关问题中有着重要的作用。
4.求解带权路径长度的算法利用非递归后序遍历,我们可以求解树中的带权路径长度。
具体的算法思路如下:•我们使用非递归后序遍历来遍历树的所有节点。
•在遍历的过程中,我们维护一个变量来记录当前节点到根节点的路径长度之和。
•当遍历到叶子节点时,我们将当前节点的路径长度加到带权路径长度中。
•我们就可以得到树的带权路径长度。
5.个人观点和理解在我看来,非递归后序遍历求解带权路径长度是一种非常巧妙的算法设计。
它充分利用了树的特点和后序遍历的思想,通过栈来模拟递归的过程,实现了高效的算法。
而带权路径长度作为一种重要的树的指标,可以帮助我们更好地理解树的结构和特性。
这种算法不仅能够提高我们对树的认识,还能够在实际问题中得到应用。
6.总结通过本文的讨论,我们深入探讨了非递归后序遍历求解带权路径长度的算法。
我们首先介绍了非递归后序遍历的基本概念,然后讨论了树的带权路径长度以及如何利用非递归后序遍历来求解。
我分享了自己的观点和理解。
我相信通过本文的阅读,你不仅对非递归后序遍历有了更深入的理解,也对树的带权路径长度有了更全面的认识。
二叉树后序遍历非递归算法的改进研究

算法提供了一种思路.
2 . 1 利用 “ 先序遍 历 ” 思想 进行 二叉树 后序遍 历
二叉树 的后序 遍历操 作定 义 为先访 问左子 树 , 再访 问右 子 树 , 最 后 访 问根 …. 根据该定义 , 可 以
很容易设计 出后序遍历的递归算法 , 而其非递归算
法 的设计则 比较 麻烦 . 因 为在 后 序 遍 历过 程 中 , 要
保证 左孩子 和右孩 子都 已被访 问 , 并 且左 孩子 在右
二叉树 先序 遍历 的思 想是先 访 问根 结点 , 再访
问左孩 子 , 最 后访 问右 孩 子 . 对 于 二叉 树 中的任 一 结点 , 都 可看 做是 根结 点 , 因此可 以直接 访 问 , 访 问
孩 子前访 问才能访 问根结 点 , 这就 为算法 的设计 带
操作的基础. 二叉树 的遍历主要有先序遍历 、 中序 遍 历和后 序遍历 三种 . 由于二 叉树 的定 义本身 就是
递 归定义 , 因此 采 用 递 归 的 方 法 实 现 二 叉 树 的先 序、 中序和 后序三 种遍历 不仅 容易 理解 而且代 码很 简 洁. 而对 于二叉 树 的遍 历若 采 用 非 递 归 的方 法 ,
动, 最后 回到根结 点的 曲线来访 问每个 结点 , 按 照结
2 =叉 捌后序遍历非递归算法的改进思路
二 叉树后 序遍 历 操 作 要 求 访 问 的 顺 序 是 “ 左
①
收稿 日期 : 2 0 1 3—1 0—1 7 作者简 介: 章晓勤 , 女, 安徽 安庆太湖人 , 安徽电子信 息职业技术学院 , 讲师 , 工程硕士 , 研究方 向: 软件工程.
来 了难 题 】 . 为 了解 决 这一 难 题 , 研 究 人员 提 出 了
C++二叉树的先序,中序,后序遍历

C++⼆叉树的先序,中序,后序遍历三种遍历⽅式都分为递归与⾮递归的⽅式。
三种遍历⽅式的递归思想相同。
后序遍历⾮递归⽅法分为两种,具体见代码。
构造⽅式:1 #include<iostream>2 #include<stack>3using namespace std;45 typedef struct BiTNode{6char data;7int lvisited,rvisited;//左、右孩⼦是否访问过,1表⽰已访问(此项只在后序⾮递归2算法中需要)8struct BiTNode *lchild,*rchild;9 }BiTNode,*BiTree;1011void InitBiTree(BiTree &T)//构造空⼆叉树12 {13 T=NULL;14 }15void CreateBiTree(BiTree &T)//⽣成⼆叉树16 {17char ch;18 cin>>ch;19if(ch=='0')//0代表空20 T=NULL;21else22 {23 T=(BiTree)malloc(sizeof(BiTNode));//⽣成根结点24if(!T)25 {26 cout<<"⽣成结点错误!"<<endl;27return;28 }29 T->data=ch;30 T->lvisited=0;31 T->rvisited=0;32 CreateBiTree(T->lchild);33 CreateBiTree(T->rchild);34 }35 }三种遍历⽅式代码:1void PreOrder(BiTree T)//先序递归遍历2 {3if(T!=NULL)4 {5 cout<<T->data<<"";6 PreOrder(T->lchild);7 PreOrder(T->rchild);8 }9 }10void SqlPreOrder(BiTree T)//先序⾮递归遍历11 {12 stack<BiTree> s;13 BiTree p=T;14while(p || !s.empty())15 {16if(p)17 {18 cout<<p->data<<"";19 s.push(p);20 p=p->lchild;21 }22else23 {24 p=s.top();25 p=p->rchild;26 s.pop();27 }28 }29 }30313233void InOrder(BiTree T)//中序递归遍历34 {35if(T!=NULL)36 {37 InOrder(T->lchild);38 cout<<T->data<<"";39 InOrder(T->rchild);40 }41 }42void SqInOrder(BiTree T)//中序⾮递归遍历43 {44 stack<BiTree> s;45 BiTree p=T;46while(p || !s.empty())47if(p)48 {49 s.push(p);50 p=p->lchild;51 }52else53 {54 p=s.top();55 cout<<p->data<<"";56 s.pop();57 p=p->rchild;58 }59 }60616263void PostOrder(BiTree T)//后序递归遍历64 {65if(T!=NULL)66 {67 PostOrder(T->lchild);68 PostOrder(T->rchild);69 cout<<T->data<<"";70 }71 }7273//后序⾮递归遍历1思路:因为后序⾮递归遍历⼆叉树的顺序是先访问左⼦树,再访问后⼦树,最后 74//访问根结点。
三种遍历方法

三种遍历方法一、前序遍历前序遍历是二叉树遍历的一种方法,也是最常见的遍历方式之一。
在前序遍历中,首先访问根节点,然后递归地遍历左子树,最后递归地遍历右子树。
前序遍历的应用非常广泛,例如在二叉树的构建和重建、树的深度优先搜索等问题中都会用到前序遍历。
在进行前序遍历时,可以采用递归或者非递归的方式。
1. 递归实现前序遍历:递归实现前序遍历非常简单,具体步骤如下:- 首先判断当前节点是否为空,若为空则返回;- 访问当前节点;- 递归遍历左子树;- 递归遍历右子树。
2. 非递归实现前序遍历:非递归实现前序遍历需要借助栈来实现,具体步骤如下:- 将根节点入栈;- 循环执行以下步骤,直到栈为空:- 弹出栈顶节点,并访问该节点;- 若该节点的右子节点不为空,则将右子节点入栈;- 若该节点的左子节点不为空,则将左子节点入栈。
二、中序遍历中序遍历是二叉树遍历的另一种方法,同样也是一种常用的遍历方式。
在中序遍历中,首先递归地遍历左子树,然后访问根节点,最后递归地遍历右子树。
中序遍历的应用也非常广泛,例如在二叉搜索树的操作中,中序遍历可以按照升序输出所有节点的值。
1. 递归实现中序遍历:递归实现中序遍历的步骤如下:- 首先判断当前节点是否为空,若为空则返回;- 递归遍历左子树;- 访问当前节点;- 递归遍历右子树。
2. 非递归实现中序遍历:非递归实现中序遍历同样需要借助栈来实现,具体步骤如下:- 将根节点入栈;- 循环执行以下步骤,直到栈为空:- 若当前节点不为空,则将当前节点入栈,并将当前节点指向其左子节点;- 若当前节点为空,则弹出栈顶节点,并访问该节点,然后将当前节点指向其右子节点。
三、后序遍历后序遍历是二叉树遍历的另一种方式,也是最后一种常见的遍历方式。
在后序遍历中,首先递归地遍历左子树,然后递归地遍历右子树,最后访问根节点。
后序遍历的应用也非常广泛,例如在二叉树的删除操作中,需要先删除子节点,再删除根节点。
数据结构中二叉树的生成及遍历非递归算法浅析

及运算 都较为简练 , 因此 , 二叉树 在数据结构课 程 中显得 特别 c a dt; hr aa s ut to eci , hd t c bnd h dr i ; r l l cl 二叉树是 由结点的有 限集合构成 ,这个有限集合或者为空 }t e Br ; e 集 ,或者是 由一个根节点及两棵互不相交的分别称之为这个根 Bre [ as e t Q m xi ] e z;
一
、
引言
# c d “aoh il e m1 ・ nu ] ” c
t ee。 c b oe y d t t t d{ p n
、
二叉树是一种重要 的树形结构 , 其结构规整。许多实际问 # en U L0 df e L i N
题抽象 出来 的数据结构往往是二叉树 的形式 , 而且其存储结构 重要 , 这里 我们先 了解一下二叉树 。
,
立二 叉链表。 一般的二 对于 叉树, 必须添加一些 虚结点, 使其成 ‘ ~’ : 一 、
队列是一个指针类型 的数组 , 保存已输入 的结点 _… 、
… ~ … 一 ’
,
# e n x i 0 d f ema sz 1 0 i e 衔n l d sdoh” cu e“ t i.
s> 一
l= L ; d U L
r a+ ; e r +
Qra1s r ; e =
。
3 办公 自动化杂志 o。
i ra- 1T s f er= )= : ( =
es le
f=t kt ] T s c [p; a o
近 >i = p 卜 r =) 曲t
fr f“ " - dt ; pi (%c , > aa n T )
递归算法 , 故有关二叉树的试题通 常要求采用非递归算 法, 这就 Br , ; te e s 使得掌握二叉树的生成及遍历的非递归算法成为必要 。 tN I ; = uJ L
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
后序遍历非递归算法
typedef enum{L,R} tagtype;
typedef struct
{
Bitree ptr;
tagtype tag;
}stacknode;
typedef struct
{
stacknode Elem[maxsize];
int top;
}SqStack;
void PostOrderUnrec(Bitree t)
{
SqStack s;
stacknode x;
StackInit(s);
p=t;
do
{
while (p!=null) //遍历左子树
{
x.ptr = p;
x.tag = L; //标记为左子树
push(s,x);
p=p->lchild;
}
while (!StackEmpty(s) && s.Elem[s.top].tag==R)
{
x = pop(s);
p = x.ptr;
visite(p->data); //tag为R,表示右子树访问完毕,故访问根结点}
if (!StackEmpty(s))
{
s.Elem[s.top].tag =R; //遍历右子树
p=s.Elem[s.top].ptr->rchild;
}
}while (!StackEmpty(s));
}//PostOrderUnrec
后序算法之二
void BT_PostOrderNoRec(pTreeT root)
{
stack<treeT *> s;
pTreeT pre=NULL;
while ((NULL != root) || !s.empty())
{
if (NULL != root)
{
s.push(root);
root = root->left;
}
else
{
root = s.top();
if (root->right!=NULL && pre!=root->right)
{
root=root->right;
}
else
{
root=pre=s.top();
visit(root);
s.pop();
root=NULL;
}
}
}
}
一个比较容易理解的后序遍历:
void PostOrder(Bitree *t)
{
TreeNode *node = NULL,*last = NULL;
Stack s;
s,Init();
s.push(t);
while(!s.IsEmpty())
{
node = s.pop();
if(last == node->left || last == node->right)//左右子树已经访问完了,该访问根节点了
{
visit(node);
last = node;
}
else if(node->left || node->right) //左右子树未访问,当前节点入栈,左右节点入栈
{
s.push(node);
if(node->right)
s.push(node->right);
if(node->left)
s.push(node->left);
}
else //当前节点为叶节点,访问
{
visit(node);
last = node;
}
}
}。