二叉树非递归后序遍历
- 格式:docx
- 大小:53.78 KB
- 文档页数:7
后序遍历的非递归算法(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;```以上代码中,我们使用了一个辅助数组作为栈来实现非递归遍历。
⼆叉树遍历(前序、中序、后序、层次、⼴度优先、深度优先遍历)⽬录转载:⼆叉树概念⼆叉树是⼀种⾮常重要的数据结构,⾮常多其他数据结构都是基于⼆叉树的基础演变⽽来的。
对于⼆叉树,有深度遍历和⼴度遍历,深度遍历有前序、中序以及后序三种遍历⽅法,⼴度遍历即我们寻常所说的层次遍历。
由于树的定义本⾝就是递归定义,因此採⽤递归的⽅法去实现树的三种遍历不仅easy理解并且代码⾮常简洁,⽽对于⼴度遍历来说,须要其他数据结构的⽀撑。
⽐⽅堆了。
所以。
对于⼀段代码来说,可读性有时候要⽐代码本⾝的效率要重要的多。
四种基本的遍历思想前序遍历:根结点 ---> 左⼦树 ---> 右⼦树中序遍历:左⼦树---> 根结点 ---> 右⼦树后序遍历:左⼦树 ---> 右⼦树 ---> 根结点层次遍历:仅仅需按层次遍历就可以⽐如。
求以下⼆叉树的各种遍历前序遍历:1 2 4 5 7 8 3 6中序遍历:4 2 7 5 8 1 3 6后序遍历:4 7 8 5 2 6 3 1层次遍历:1 2 3 4 5 6 7 8⼀、前序遍历1)依据上⽂提到的遍历思路:根结点 ---> 左⼦树 ---> 右⼦树,⾮常easy写出递归版本号:public void preOrderTraverse1(TreeNode root) {if (root != null) {System.out.print(root.val+" ");preOrderTraverse1(root.left);preOrderTraverse1(root.right);}}2)如今讨论⾮递归的版本号:依据前序遍历的顺序,优先訪问根结点。
然后在訪问左⼦树和右⼦树。
所以。
对于随意结点node。
第⼀部分即直接訪问之,之后在推断左⼦树是否为空,不为空时即反复上⾯的步骤,直到其为空。
若为空。
则须要訪问右⼦树。
注意。
在訪问过左孩⼦之后。
⼆叉树遍历(前中后序遍历,三种⽅式)⽬录刷题中碰到⼆叉树的遍历,就查找了⼆叉树遍历的⼏种思路,在此做个总结。
对应的LeetCode题⽬如下:,,,接下来以前序遍历来说明三种解法的思想,后⾯中序和后续直接给出代码。
⾸先定义⼆叉树的数据结构如下://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> preorderTraversal(TreeNode* root) {if(root == NULL) return {};vector<int> res;helper(root,res);return res;}void helper(TreeNode *root, vector<int> &res){res.push_back(root->val);if(root->left) helper(root->left, res);if(root->right) helper(root->right, res);}};使⽤辅助栈迭代实现:算法为:先把根节点push到辅助栈中,然后循环检测栈是否为空,若不空,则取出栈顶元素,保存值到vector中,之后由于需要想访问左⼦节点,所以我们在将根节点的⼦节点⼊栈时要先经右节点⼊栈,再将左节点⼊栈,这样出栈时就会先判断左⼦节点。
代码如下:class Solution {public:vector<int> preorderTraversal(TreeNode* root) {if(root == NULL) return {};vector<int> res;stack<TreeNode*> st;st.push(root);while(!st.empty()){//将根节点出栈放⼊结果集中TreeNode *t = st.top();st.pop();res.push_back(t->val);//先⼊栈右节点,后左节点if(t->right) st.push(t->right);if(t->left) st.push(t->left);}return res;}};Morris Traversal⽅法具体的详细解释可以参考如下链接:这种解法可以实现O(N)的时间复杂度和O(1)的空间复杂度。
c语言二叉树的先序,中序,后序遍历1、先序遍历先序遍历可以想象为,一个小人从一棵二叉树根节点为起点,沿着二叉树外沿,逆时针走一圈回到根节点,路上遇到的元素顺序,就是先序遍历的结果先序遍历结果为:A B D H I E J C F K G2、中序遍历中序遍历可以看成,二叉树每个节点,垂直方向投影下来(可以理解为每个节点从最左边开始垂直掉到地上),然后从左往右数,得出的结果便是中序遍历的结果中遍历结果为:H D I B E J A F K C G3、后序遍历后序遍历就像是剪葡萄,我们要把一串葡萄剪成一颗一颗的。
还记得我上面提到先序遍历绕圈的路线么?(不记得翻上面理解)就是围着树的外围绕一圈,如果发现一剪刀就能剪下的葡萄(必须是一颗葡萄)(也就是葡萄要一个一个掉下来,不能一口气掉超过1个这样),就把它剪下来,组成的就是后序遍历了。
后序遍历中,根节点默认最后面后序遍历结果:H I D J E B K F G C A4、口诀先序遍历:先根再左再右中序遍历:先左再根再右后序遍历:先左再右再根这里的根,指的是每个分叉子树(左右子树的根节点)根节点,并不只是最开始头顶的根节点,需要灵活思考理解5、代码展示#include<stdio.h>#include<stdlib.h>typedef struct Tree{int data; // 存放数据域struct Tree *lchild; // 遍历左子树指针struct Tree *rchild; // 遍历右子树指针}Tree,*BitTree;BitTree CreateLink(){int data;int temp;BitTree T;scanf("%d",&data); // 输入数据temp=getchar(); // 吸收空格if(data == -1){ // 输入-1 代表此节点下子树不存数据,也就是不继续递归创建return NULL;}else{T = (BitTree)malloc(sizeof(Tree)); // 分配内存空间T->data = data; // 把当前输入的数据存入当前节点指针的数据域中printf("请输入%d的左子树: ",data);T->lchild = CreateLink(); // 开始递归创建左子树printf("请输入%d的右子树: ",data);T->rchild = CreateLink(); // 开始到上一级节点的右边递归创建左右子树return T; // 返回根节点}}// 先序遍历void ShowXianXu(BitTree T) // 先序遍历二叉树{if(T==NULL) //递归中遇到NULL,返回上一层节点{return;}printf("%d ",T->data);ShowXianXu(T->lchild); // 递归遍历左子树ShowXianXu(T->rchild); // 递归遍历右子树}// 中序遍历void ShowZhongXu(BitTree T) // 先序遍历二叉树{if(T==NULL) //递归中遇到NULL,返回上一层节点{return;}ShowZhongXu(T->lchild); // 递归遍历左子树printf("%d ",T->data);ShowZhongXu(T->rchild); // 递归遍历右子树}// 后序遍历void ShowHouXu(BitTree T) // 后序遍历二叉树{if(T==NULL) //递归中遇到NULL,返回上一层节点{return;}ShowHouXu(T->lchild); // 递归遍历左子树ShowHouXu(T->rchild); // 递归遍历右子树printf("%d ",T->data);}int main(){BitTree S;printf("请输入第一个节点的数据:\n");S = CreateLink(); // 接受创建二叉树完成的根节点printf("先序遍历结果: \n");ShowXianXu(S); // 先序遍历二叉树printf("\n中序遍历结果: \n");ShowZhongXu(S); // 中序遍历二叉树printf("\n后序遍历结果: \n");ShowHouXu(S); // 后序遍历二叉树return 0;}。
前序后序中序详细讲解1.引言1.1 概述在数据结构与算法中,前序、中序和后序是遍历二叉树的三种基本方式之一。
它们是一种递归和迭代算法,用于按照特定的顺序访问二叉树的所有节点。
通过遍历二叉树,我们可以获取有关树的结构和节点之间关系的重要信息。
前序遍历是指先访问根节点,然后递归地访问左子树,最后递归地访问右子树。
中序遍历是指先递归地访问左子树,然后访问根节点,最后递归地访问右子树。
后序遍历是指先递归地访问左子树,然后递归地访问右子树,最后访问根节点。
它们的不同之处在于访问根节点的时机不同。
前序遍历可以帮助我们构建二叉树的镜像,查找特定节点,或者获取树的深度等信息。
中序遍历可以帮助我们按照节点的大小顺序输出树的节点,或者查找二叉搜索树中的某个节点。
后序遍历常用于删除二叉树或者释放二叉树的内存空间。
在实际应用中,前序、中序和后序遍历算法有着广泛的应用。
它们可以用于解决树相关的问题,例如在Web开发中,树结构的遍历算法可以用于生成网页导航栏或者搜索树结构中的某个节点。
在图像处理中,前序遍历可以用于图像压缩或者图像识别。
另外,前序和后序遍历算法还可以用于表达式求值和编译原理中的语法分析等领域。
综上所述,前序、中序和后序遍历算法是遍历二叉树的重要方式,它们在解决各种与树有关的问题中扮演着关键的角色。
通过深入理解和应用这些遍历算法,我们可以更好地理解和利用二叉树的结构特性,并且能够解决更加复杂的问题。
1.2文章结构文章结构是指文章中各个部分的布局和组织方式。
一个良好的文章结构可以使读者更好地理解和理解文章的内容。
本文将详细讲解前序、中序和后序三个部分的内容和应用。
首先,本文将在引言部分概述整篇文章的内容,并介绍文章的结构和目的。
接下来,正文部分将分为三个小节,分别对前序、中序和后序进行详细讲解。
在前序讲解部分,我们将定义和解释前序的意义,并介绍前序在实际应用中的场景。
通过详细的解释和实例,读者将能更好地理解前序的概念和用途。
二叉树的遍历学习心得 (4)二叉树是一种重要的数据结构,在计算机科学领域中被广泛应用。
对二叉树的遍历是对树进行操作和处理的重要方法之一。
二叉树遍历包括先序遍历、中序遍历和后序遍历三种,每种遍历方式都有它的特点和应用场景。
在本文中,我将结合自己的学习经历,介绍二叉树遍历的相关知识,并分享我的学习心得。
一、什么是二叉树遍历?二叉树遍历指的是按照某种次序访问二叉树的所有节点。
具体来说,遍历过程中所有节点都会被访问且只会被访问一次。
遍历是二叉树最基本的操作之一,它能够帮助我们遍历整个二叉树,并且可以实现二叉树的各种功能。
二、二叉树遍历的种类1. 先序遍历:先访问根节点,然后按照左子树到右子树的顺序依次访问所有的节点。
2. 中序遍历:按照左子树、根节点、右子树的顺序依次访问所有的节点。
3. 后序遍历:按照左子树、右子树、根节点的顺序依次访问所有的节点。
在学习二叉树遍历时,首先需要掌握各种遍历方式的定义和遍历过程。
我们需要了解如何通过递归或非递归的方式来实现二叉树的遍历。
三、学习心得在学习二叉树遍历时,我发现遍历过程中需要注意以下几点:1. 二叉树的遍历是递归算法的经典应用之一。
在递归调用时,需要注意传递和保存上一层函数中的参数和变量,以及返回值的传递和处理。
2. 在遍历时需要针对每个节点进行相应的操作,比如修改节点值、计算节点的数值、输出节点信息等等。
3. 非递归遍历时需要使用栈或队列辅助存储节点信息,在遍历时需要注意栈或队列的操作和数据结构实现。
通过实践,我逐渐掌握了二叉树遍历的基本思想,学会了如何根据需要选择不同的遍历方式。
同时,我也深刻体会到学习算法需要循序渐进、一步步地进行,并且需要强化巩固,多多实践才能真正掌握。
四、总结二叉树遍历是数据结构中的重要主题之一,是学习和掌握二叉树等数据结构算法的基础。
学习时需要理解各种遍历方式的定义和遍历过程,对递归和非递归实现进行深入的练习和掌握,通过不断地巩固和实践,最终能够掌握二叉树遍历的基本思想和实现方法。
后序遍历非递归算法后序遍历是二叉树遍历中的一种,它的遍历顺序是先访问左子树、再访问右子树、最后访问根节点。
在非递归算法中,我们需要借助栈来实现后序遍历。
具体步骤如下: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); }}以上算法采⽤先序遍历输出了所有的叶⼦节点,所以叶⼦节点是从左到右输出的。
数据结构上机实验大作业
年月日
算法完整源程序:(关键语句需加注释)
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
char data;
struct node *lchild, *rchild;
}BinTNode;
typedef struct StackNode
{
BinTNode node;
int rvisited;
int from;
}StackNode;
StackNode s[20]; //定义顺序栈
StackNode* esp=&s[0]; //栈顶指针
BinTNode* creat() //先序建树
{
BinTNode* t;
char x;
scanf("%c",&x);
getchar();
if(x=='0')
t=NULL;
else
{ t=(BinTNode*)malloc(sizeof(BinTNode));
t->data=x;
printf("请输入%c结点的左子结点:",t->data);
t->lchild=creat();
printf("请输入%c结点的右子结点:",t->data);
t->rchild=creat();
}
return t;
}
void push(BinTNode e,int rvisited,int f) //压栈操作{
esp++;
esp->node=e;
esp->rvisited=0;
esp->from=f;
}
BinTNode* pop(BinTNode* p ) //出栈,将栈顶的元素弹出,并把其中esp->node的地址赋值给 p {
p=&(esp->node);
esp--;
return p;
}
void show() //显示路径
{
while(esp>&s[0])
{
printf("%c",esp->node.data);
if(esp->node.data!='a') //根据from确定是来自左边还是右边
{
if(esp->from==1)
printf("右");
if(esp->from==0)
printf("左");
}
esp--;
if(esp->node.data)
printf("<---");
}
printf("\n\n");
}
void lastOrderTraverse(BinTNode* root,char search) //后序遍历树
{
BinTNode* p=root;
while(root)
{
push(*root,0,0);
root=root->lchild;
}
while(esp>&s[0])
{
if(!esp->node.rchild || esp->rvisited)
{
p=pop(p);
if(search==p->data)
{
push(*p,1,(esp+1)->from);
show();
}
}
else
{
esp->rvisited=1;
p=&(esp->node);
p=p->rchild;
push(*p,0,1);
p=p->lchild;
while(p)
{
push(*p,0,0);
p=p->lchild;
}
}
}
}
int main()
{
char c;
printf("请输入根结点的值:");
BinTNode* root=creat();
while(1)
{
printf("请输入你要查询的值:");
scanf("%c",&c);
getchar();
lastOrderTraverse(root,c);
}
return 0;
}
算法执行结果截图:二叉树举例:
执行结果:。