最近上课写了一个二叉树非递归的相关题目,之前学习的时候没有认真学,导致现在写起来非常麻烦(ε=(´ο`*)))唉)于是又查阅了很多的资料来写这个题目,题目描述很简单如下:
求二叉树上结点的路径 设计要求:在采用链式存储结构存储的二叉树上,以bt指向根结点,
p指向任一给定的结点,编程实现求出从根结点到给定结点之间的路
径。
- 建立二叉树存储结构
- 求二叉树的前序遍历
- 求二叉树的中序遍历
- 求二叉树的后序遍历
- 求指定结点的路径
提示:
【采用非递归遍历的方法】 1. 二叉树的建立 2. 求指定结点的路径 3. 二叉树的前、中、后序非递归遍历算法 4. 查找函数
下面就是我的代码部分
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#define MAXSIZE 100
typedef struct Node{
char data;
int flag;//flag=0左右子树没有设置;flag=1左子树设置,右子树没有设置;flag=2出栈条件;
struct Node *lchild;
struct Node *rchild ;
}BiTree;
BiTree* Create(BiTree *p){//先序遍历非递归建立二叉树
//创建二叉树,非递归算法
BiTree *stack[MAXSIZE]; //定义栈
int top = -1; //初始化栈
p = (BiTree *)malloc(sizeof(BiTree)); //创建根节点
char x;
scanf("%c", &x);
p->data = x;
p->flag = 0;
stack[++top] = p; //根结点进栈
while(top != -1){
char x;
scanf("%c", &x);
if(x == '.'){
//“.”空结点的表示方式
if(stack[top]->flag == 0){
stack[top]->flag = 1;
stack[top]->lchild = NULL;
}
else if(stack[top]->flag == 1){
stack[top]->flag = 2;
stack[top]->rchild = NULL;
}
}
else{
BiTree *q = (BiTree*)malloc(sizeof(BiTree));
q->data = x;
q->flag = 0;
if(stack[top]->flag == 0){
//先插左子树
stack[top]->lchild = q;
stack[top]->flag = 1;
stack[++top] = q;
}
else if(stack[top]->flag == 1){
//判断是否满足插入右子树的条件
stack[top]->rchild = q;
stack[top]->flag = 2;
stack[++top] = q;
}
}
while(stack[top]->flag == 2){
//判断是否满足出栈条件,满足则连续出栈
top--;
}
}
return p;
}
void PreOrder(BiTree *b){//先序非递归便遍历
BiTree *stack[MAXSIZE];
int top=-1;//创建并初始化栈
//通过栈来实现二叉树的先序遍历,先输出根节点,然后遍历左子树,若左子树为空,则出栈该节点
//转入右子树,
while(b || top!=-1){
if(b) {
printf("%c ",b->data);
stack[++top]=b; //入栈
b=b->lchild;//一直向左直到叶子节点
}
else{
b=stack[top--];//出栈叶子节点
b=b->rchild;//寻找右子树
}
}
printf("\n");
}
void InOrder(BiTree *b){//后序非递归遍历
BiTree *stack[100];
int top=-1;//初始化栈 ,
while(b || top!=-1){
if(b){
stack[++top]=b;//先将节点入栈,找到左子树叶子节点
b=b->lchild;
}
else{
b=stack[top--]; //最左边叶子节点出栈
printf("%c ",b->data);//输出最左边叶子节点
b=b->rchild;
}
}
printf("\n");
}
void PostOrder(BiTree *b){
//后续非递归遍历是先访问左子树,再访问右子树最后根节点
//1.沿着左孩子,依次入栈,直到左孩子为空。此时栈内元素 A,B,D;
//2、读栈顶元素,若其右孩子不为空且没有访问过,将转右子树执行 1;
//否则栈顶元素出栈并访问
BiTree *r=NULL;
BiTree *stack[100];
int top=-1;
while(b!=NULL ||top!=-1){
if(b!=NULL){
stack[++top]=b;//沿着左孩子依次入栈
b=b->lchild;
}
else{
b=stack[top];//取栈顶节点
if(b->rchild!=NULL && b->rchild!=r){//如果有字数存在,并且未被访问过,转向右子树
b=b->rchild;
}
else{//否则出栈节点并访问
printf("%c ",stack[top--]->data);
r=b;//记录最近访问节点
b=NULL;// 重置b指针
}
}
}
printf("\n");
}
void LeavelOrder(BiTree *b){
BiTree *queue[100];
int front=0;
int rear=0;
queue[rear++]=b;
while(rear!=front){
printf("%4c",queue[front++]->data);
if(b->lchild!=NULL){
queue[rear++]=b;
}
if(b->rchild!=NULL){
queue[rear++]=b;
}
}
}
void paths(BiTree *B,char a){
BiTree *b=B;
BiTree *stack[MAXSIZE];
int top=-1;//创建并初始化栈
BiTree *last=NULL;
while(b!=NULL || top!=-1){
if(b!=NULL) {
stack[++top]=b; //入栈
if(b->data==a){
printf("找到了目标节点\n");
printf("路径是:");
while(top!=-1){
printf("%c",stack[top]->data);
top--;
if(top!=-1){
printf("->");
}
}
printf("\n");
return ;
}
b=b->lchild;//一直向左直到叶子节点
}
else{
BiTree * t=stack[top];//出栈叶子节点
if(t->rchild && t->rchild!=last){
b=t->rchild;
}
else{
last=stack[top--];
}
}
}
printf("没有找到该节点\n");
}
int main(){
BiTree *b;
printf("请按照先序输入二叉树元素:");
b=Create(b);
printf("先序遍历:");
PreOrder(b);
printf("中序遍历:");
InOrder(b);
printf("后序遍历:");
PostOrder(b);
printf("请输入要查找路径元素:");
char a;
getchar();//读取创建二叉树时缓冲区的最后一个回车
scanf("%c",&a);
paths(b,a);
return 0;
}
我写了一下相关的思路仅供参考!
先定义二叉树结构体,定数数据区data,左右孩子节点rchild和lchild,以及flag用作创建二叉树是确定左右节点是否存在(flag=0左右节点都没有创建,flag=1右节点没有创建,flag=2左右节点都已经创建成功)。
1、 题目要求使用非递归的方法实现二叉树的一系列操作,首先是二叉树的建立,我采用了先序非递归的方法建立的二叉树,利用非递归实现需要借助栈来实现,利用“.”来表示空节点。利用站不为空循环先插入左子树,等到左子树全部插入完毕之后即flag=1时再对右子树进行插入,等到flag=2,满足出栈条件。
2、 二叉树的先序非递归建立也是使用栈来完成,先输出根节点,然后将根节点入栈,遍历其左子树到叶子节点,然后转向右子树,不断出栈;
3、 中序遍历跟前序便利类似,只不过是先入栈等到左子树的叶子节点时出栈叶子节点然后逐渐出栈遍历。
4、 后序遍历先访问左节点然后右节点最后父亲节点,首先沿着左孩子一直入栈,知道左孩子为空,然后访问栈顶元素,判断栈顶元素的有孩子是否为空或者访问过,如果不是则转向右子树在执行想左子树遍历。
5、 非递归寻找二叉树的节点路径问题,首先依旧是采用栈来实现,然后我使用了先序遍历来寻找这个节点,如果找到这个节点就输出栈内的元素。
如果有错误还请指正。