vlambda博客
学习文章列表

二叉树后续非递归遍历(很多人的盲区?)

点击上方一键关注 Python变成爱好者!

回复“资料馆”,获取几百本优质PDF书籍

Python编程爱好者
用Python语言去解决一切吧🤨🤨 ~~~ 资料馆- 百本电子书,获取几百本Python电子书籍
92篇原创内容
Official Account

学而知不足,长按关注,精彩不错过

大家好,我是Johngo!

今天有在校的粉丝想要C语言实现的树的后续遍历的详细讲解,今天就来看看。

后面给到了所有的代码,可以直接运行!


二叉树后序遍历

二叉树的遍历方式主要由先序遍历、中序遍历和后续遍历,后就是层次遍历

本节就先来看看后序遍历,后面会把其他几种遍历方式发出,也会用不同的语言来实现


后序遍历过程

a. 先序遍历其左子树;

b. 先序遍历其右子树;

c. 访问根节点;

然后就是一直递归下去,在访问到节点的时候,可以进行节点的相关处理,比如说简单的访问节点值

下图是一棵二叉树,我们来手动模拟一下后序遍历过程

二叉树后续非递归遍历(很多人的盲区?)


按照上述后序遍历的过程,得到后序遍历序列:

H I D E B F G C A


递归实现

二叉树的后序遍历利用上述的递归思想进行C语言代码实现:

树形结构按照上述树形结构进行初始化

# include <stdio.h># include <string.h># include <stdlib.h># define ElementType char
//结点结构体typedef struct BinTNode{ ElementType data; struct BinTNode * left; struct BinTNode * right;}BinTNode, *BinTree;
// 初始化树形结构BinTNode * CreateBiTree(BinTNode *T){ T=(BinTNode*)malloc(sizeof(BinTNode)); T->data='A'; T->left=(BinTNode*)malloc(sizeof(BinTNode)); T->left->data='B'; T->right=(BinTNode*)malloc(sizeof(BinTNode)); T->right->data='C'; T->left->left=(BinTNode*)malloc(sizeof(BinTNode)); T->left->left->data='D'; T->left->right=(BinTNode*)malloc(sizeof(BinTNode)); T->left->right->data='E'; T->left->right->left=NULL; T->left->right->right=NULL; T->left->left->left=(BinTNode*)malloc(sizeof(BinTNode)); T->left->left->left->data='H'; T->left->left->left->left=NULL; T->left->left->left->right=NULL; T->left->left->right=(BinTNode*)malloc(sizeof(BinTNode)); T->left->left->right->data='I'; T->left->left->right->left=NULL; T->left->left->right->right=NULL; T->right->left=(BinTNode*)malloc(sizeof(BinTNode)); T->right->left->data='F'; T->right->left->left=NULL; T->right->left->right=NULL; T->right->right=(BinTNode*)malloc(sizeof(BinTNode)); T->right->right->data='G'; T->right->right->left=NULL; T->right->right->right=NULL;
return T;}
// 遍历过程中,输出节点值void printElement(BinTNode * T){ printf("%c ",T->data);}
//先序遍历void PostOrderTraverse(BinTNode * T){ if (T) { PostOrderTraverse(T->left); //递归访问左孩子 PostOrderTraverse(T->right); //递归访问右孩子 printElement(T); //输出节点值 } // 当节点为空的时候,返回 return;}
int main() { BinTNode * Tree; Tree = CreateBiTree(Tree); // 初始化树形结构 printf("后序遍历: "); PostOrderTraverse(Tree); // 先序递归进行 printf("\n"); // 最后换行 return 0;}

运行结果:

后序遍历: H I D E B F G C A



非递归实现

相比于之前的先序遍历和中序遍历非递归实现,后序遍历的非递归算法与之前有所不同,后续遍历需要先访问左右子结点后,才能访问该结点,而这也是非递归的难点所在。

考虑了几种实现的方案,这里我给出我认为比较清晰的一个方案供大家参考:借助两个栈(S1和S2)来进行操作

看下面伪代码:

初始化S1的top元素是树的根结点;while(top1 != -1) { 将栈顶元素push到S2; if(栈顶元素有孩子结点){ 按照孩子结点的左右顺序push进S1; } }循环逐个弹出S2的栈顶元素


伪代码可能看了之后有些不太好懂,但是还算看着清晰吧,下面借助图,一定会思路清晰的(长图发放):

二叉树后续非递归遍历(很多人的盲区?)

有了这个思路就应该会很清晰了,下面按照上述思路用C语言实现:

#include <stdio.h>#include <string.h>#include <stdlib.h>#define ElementType charint top_S1 = -1; //定义栈S1 top下标int top_S2 = -1; //定义栈S2 top下标
// 结点结构体typedef struct BinTNode{ ElementType data; struct BinTNode * left; struct BinTNode * right;}BinTNode, *BinTree;
// 初始化树形结构BinTNode * CreateBiTree(BinTNode *T) { T=(BinTNode*)malloc(sizeof(BinTNode)); T->data='A'; T->left=(BinTNode*)malloc(sizeof(BinTNode)); T->left->data='B'; T->right=(BinTNode*)malloc(sizeof(BinTNode)); T->right->data='C'; T->left->left=(BinTNode*)malloc(sizeof(BinTNode)); T->left->left->data='D'; T->left->right=(BinTNode*)malloc(sizeof(BinTNode)); T->left->right->data='E'; T->left->right->left=NULL; T->left->right->right=NULL; T->left->left->left=(BinTNode*)malloc(sizeof(BinTNode)); T->left->left->left->data='H'; T->left->left->left->left=NULL; T->left->left->left->right=NULL; T->left->left->right=(BinTNode*)malloc(sizeof(BinTNode)); T->left->left->right->data='I'; T->left->left->right->left=NULL; T->left->left->right->right=NULL; T->right->left=(BinTNode*)malloc(sizeof(BinTNode)); T->right->left->data='F'; T->right->left->left=NULL; T->right->left->right=NULL; T->right->right=(BinTNode*)malloc(sizeof(BinTNode)); T->right->right->data='G'; T->right->right->left=NULL; T->right->right->right=NULL;
return T;}
// 栈S1 - 进栈pushvoid push_S1(BinTNode** stack,BinTNode * elem) { stack[++top_S1] = elem;}
// 栈S2 - 进栈pushvoid push_S2(BinTNode** stack,BinTNode * elem) { stack[++top_S2] = elem;}
//栈S1 - 弹栈popvoid pop_S1(){ if (top_S1 == -1) { return ; } top_S1--;}
//栈S2 - 弹栈popvoid pop_S2(){ if (top_S2 == -1) { return ; } top_S2--;}
// 遍历过程中,输出结点值void printElement(BinTNode* elem) { printf("%c ",elem->data);}
//获取栈顶元素BinTNode * getTop_S1(BinTNode** stack){ return stack[top_S1];}
//获取栈顶元素BinTNode * getTop_S2(BinTNode** stack){ return stack[top_S2];}
//非递归遍历 - 左右根void PostOrderTraverse(BinTNode * Tree) { BinTNode * S1[30]; // 辅助栈 BinTNode * S2[30]; BinTNode * T = Tree; // 定义临时指针 BinTNode * Temp; push_S1(S1, T); // 初始化S1的top元素是树的根结点 while(top_S1 != -1) { T = getTop_S1(S1); // S1的栈顶元素弹出 pop_S1(); // 栈顶元素弹栈 push_S2(S2, T);
if(T->left != NULL || T->right != NULL) { // 栈顶元素有孩子结点 if(T->left != NULL) push_S1(S1, T->left); if(T->right != NULL) push_S1(S1, T->right); } } // 逐个弹出S2的元素 while(top_S2 != -1) { printElement(getTop_S2(S2)); pop_S2(); }}
int main() { BinTNode * Tree; Tree = CreateBiTree(Tree); printf("看到这样就对了: H I D E B F G C A\n"); printf("后序遍历:\t"); PostOrderTraverse(Tree); printf("\n"); return 0;}

运行结果

看到这样就对了: H D I B E A F C G中序遍历:      H D I B E A F C G


以上就是今天的全部内容啦!


学而知不足,思而得远虑,行而能致远。

我们下期见!二叉树后续非递归遍历(很多人的盲区?)二叉树后续非递归遍历(很多人的盲区?)


往期推荐


Redis过期key删除策略以及内存淘汰策略

这个发邮件的工具,省了我半天的时间







长按上方二维码  | 扫码关注
专注数据分析、机器学习和大数据领域
后台回复 “ 资料馆 ” 获取几百本业内经典著作

👉  点赞、 在看、 转发 是对Johngo最大的鼓励Thanks♪(・ω・)ノ