数据结构之--非递归后序遍历的两种实现

大家好,我是逝去的粒子,今天带来的是非递归后序的两种实现方法,大家选取适合自己的一种即可,提高算法思想是我们的目标。


第一步:了解为什么要学习这个
1.考研数据结构需要会
2.可以提高自己的编程思想,而不是一个码农机器
3.完整代码请大家放心,我统一放在文章最后,不必担心有头没尾!

第一种思想
第一种思想也是我从网上看到的,非常感谢。具体是说:当我们借助栈存放节点,并模拟后续遍历时,会发现每一个节点都会在栈头出现2次,然后才出栈,根据这个规律,我们制定了相应的二次判断结构。

手动步骤演示
假设我们有如下这样一个二叉树,手动演示后序遍历->在这里插入图片描述
节点1进栈->第一次出现
节点2进栈->第一次出现
节点2无左子树,出栈,转向右子树,进栈->第二次出现
节点4进栈->第一次出现
节点6进栈->第一次出现
节点6寻找右子树,出栈,转向右子树,进栈->第二次出现
节点6进行出栈,符合第二次出现,出栈,不再对其进栈操作
节点4出栈,符合第二次出现,出栈
节点2出栈,符合第二次出现,出栈
节点1寻找右子树,出栈,转向右子树,进栈,->第二次出现
节点3进栈,->第一次出现
节点3寻找右子树,出栈,转向右子树,进栈,->第二次出现
…以下类推即可

代码实现

//二次判断结构
typedef struct BTNode{
	BiTNode *bnode;
	bool isFirst;
}BTNode;
bnode:是指向一个节点的指针
isFirst:是判断是否二次出现

有了判断结构之后,就可以直接写代码了,如下:

//非递归后序遍历
void PostOrder2(BiTree T){
	SqStack s;
	InitStack(s);
	BiTree p=T;
	BTNode *temp;
	while(p!=NULL||!StackEmpty(s)){
		while(p!=NULL){
			BTNode *btn=(BTNode*)malloc(sizeof(BTNode));
			btn->bnode=p;
			btn->isFirst=true;
			Push(s,btn);
			p=p->lchild;
		}
		if(!StackEmpty(s)){
			temp=Pop(s);	//接收弹出来的节点
			if(temp->isFirst==true){
				temp->isFirst=false;
				Push(s,temp);
				p=temp->bnode->rchild;
			}
			else{
				printf("%c",temp->bnode->data);
				p=NULL;
			}
		}
	}
}
代码实现的一个不同就是,我的p指针只是作为遍历用的,并不进栈,我找了一个能指向当前节点的btn节点,进行进栈出栈操作。

这样的话,我么就借助于栈和一个辅助结构进行了实现操作,只要能看懂手动演示的步骤,那么代码也就能看懂,如果觉得看不懂示意图,请下方留言,我将第一时间进行修改。

极其推荐->第二种思想:
第二种思想是我十分推荐的,简洁明了,后序遍历是:左子树->右子树->根节点,当用栈储存节点,只需分清返回根节点的,是从左子树返回的,还是从右子树返回的,所以,使用辅助指针r,指向最近访问过的节点。

代码有注释,可以边看边手动实现具体过程,加强记忆。

代码实现

void Post(BiTree &T){
	SqStack s;							//初始化栈
	InitStack(s);						
	BiTree p=T,r;						//工作指针p和r
	while(p!=NULL||!StackEmpty(s)){
		if(p){
			Push(s,p);
			p=p->lchild;
		}
		else{
			GetTop(s,p);					//栈的基本方法,在此的作用是返回当前根节点
			if(p->rchild&&p->rchild!=r){	//如果右子树存在,且未被访问过
				p=p->rchild;				//转向右
				Push(s,p);					//进栈
				p=p->lchild;				//再走到最左
			}
			else{
				Pop(s,p);					//弹栈并访问
				printf("%c",p->data);
				r=p;					//记录最近访问的节点
				p=NULL;					//节点访问完后,重置p指针
			}
		}
	}
}

结尾
可能会有同学会说,你这两个实现根本就是一个思想而已,只是用了不同的工具,确实会很相似,但是我们学习更要看重的是两个之间的小小差别,不是吗,希望会帮助到大家,谢谢。

完整代码–第一种方法

#include "stdio.h"
#include "stdlib.h"
#define MaxSize 50
typedef int ElemType;

//二叉树节点结构
typedef struct BiTNode{
	ElemType data;
	struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;

//栈的定义
//typedef struct{
//	BiTree data[MaxSize];
//	int top;
//}SqStack;

//二次判断结构
typedef struct BTNode{
	BiTNode *bnode;
	bool isFirst;
}BTNode;

typedef struct{
	BTNode* data[MaxSize];
	int top;
}SqStack;

//初始化
void InitStack(SqStack &s){
	s.top=-1;
}

//判断栈空
bool StackEmpty(SqStack &s){
	if(s.top==-1)
		return true;
	else
		return false;
}	

//进栈
/*
bool Push(SqStack &s,BiTree x){
	if(s.top==MaxSize-1){
		return false;
	}
	s.data[++s.top]=x;
	return true;
}
*/
bool Push(SqStack &s,BTNode *x){
	if(s.top==MaxSize-1){
		return false;
	}
	s.data[++s.top]=x;
	return true;
}
//出栈
/*
BiTree Pop(SqStack &s){
	BiTree x;
	if(s.top==-1){
		return false;
	}
	x=s.data[s.top--];
	return x;
}
*/
BTNode* Pop(SqStack &s){
	BTNode *x;
	if(s.top==-1){
		return false;
	}
	x=s.data[s.top--];
	return x;
}
//读取栈顶元素
/*
bool GetTop(SqStack &s){
	BiTree x;
	if(s.top==-1){
		return false;
	}
	x=s.data[s.top];
	printf("%c",x->data);
	return true;
}
*/

//默认先序输入递归创建二叉树
void CreateBiTree(BiTree &T){
	char c;
	scanf("%c",&c);
	if(c=='#')
		T=NULL;
	else{
		T=(BiTree)malloc(sizeof(BiTNode));	//创建节点
		T->data=c;
		CreateBiTree(T->lchild);
		CreateBiTree(T->rchild);
	}
}

//先序递归遍历
void PreOrder(BiTree T){
	if(T!=NULL){
		printf("%c",T->data);
		PreOrder(T->lchild);
		PreOrder(T->rchild);
	}
}

//中序递归遍历
void InOrder(BiTree T){
	if(T!=NULL){
		InOrder(T->lchild);
		printf("%c",T->data);
		InOrder(T->rchild);
	}
}

//后序递归遍历
void PostOrder(BiTree T){
	if(T!=NULL){
		PostOrder(T->lchild);
		PostOrder(T->rchild);
		printf("%c",T->data);
	}
}


//非递归后序遍历
/*
void PostOrder2(BiTree T){
	SqStack s;
	InitStack(s);
	BiTree p=T;
	BTNode *temp;
	while(p!=NULL||!StackEmpty(s)){
		while(p!=NULL){
			BTNode *btn=(BTNode*)malloc(sizeof(BTNode));
			btn->bnode=p;
			btn->isFirst=true;
			Push(s,btn);
			p=p->lchild;
		}
		if(!StackEmpty(s)){
			temp=Pop(s);	//接收弹出来的节点
			if(temp->isFirst==true){
				temp->isFirst=false;
				Push(s,temp);
				p=temp->bnode->rchild;
			}
			else{
				printf("%c",temp->bnode->data);
				p=NULL;
			}
		}
	}
}
*/

void PostOrder2(BiTree T){
	SqStack s;
	InitStack(s);	//初始化栈s
	BiTree p=T;
	BTNode *temp;
	while(p!=NULL||!StackEmpty(s)){
		while(p){
			BTNode *btn=(BTNode*)malloc(sizeof(BTNode));
			btn->bnode=p;
			btn->isFirst=true;
			Push(s,btn);
			p=p->lchild;
		}
		if(!StackEmpty(s)){
			temp=Pop(s);
			if(temp->isFirst==true){
				temp->isFirst=false;
				Push(s,temp);
				p=temp->bnode->rchild;
			}
			else{
				printf("%c",temp->bnode->data);
				p=NULL;
			}
		}
	}
}

void main(){
	BiTree T;
	CreateBiTree(T);
	PostOrder(T);
	printf("\n");
	PostOrder2(T);
	printf("\n");
}

完整代码–第二种方法

#include "stdio.h"
#include "stdlib.h"
#define MaxSize 50
typedef int ElemType;

//二叉树节点结构
typedef struct BiTNode{
	ElemType data;
	struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;

//队列的结构
typedef struct{
	BiTree data[MaxSize];		//存放队列元素
	int front,rear;				//队头指针,队尾指针
}SqQueue;

//栈的定义
typedef struct{
	BiTree data[MaxSize];
	int top;
}SqStack;

//初始化
void InitStack(SqStack &s){
	s.top=-1;
}

//判断栈空
bool StackEmpty(SqStack &s){
	if(s.top==-1)
		return true;
	else
		return false;
}	

//进栈
bool Push(SqStack &s,BiTree x){
	if(s.top==MaxSize-1){
		return false;
	}
	s.data[++s.top]=x;
	return true;
}
//出栈
bool Pop(SqStack &s,BiTree &x){
	if(s.top==-1){
		return false;
	}
	x=s.data[s.top--];
	return true;
}

//读取栈顶元素
bool GetTop(SqStack &s,BiTree &x){
	if(s.top==-1){
		return false;
	}
	x=s.data[s.top];
//	printf("%c",x->data);
	return true;
}


//默认先序输入递归创建二叉树
void CreateBiTree(BiTree &T){
	char c;
	scanf("%c",&c);
	if(c=='#')
		T=NULL;
	else{
		T=(BiTree)malloc(sizeof(BiTNode));	//创建节点
		T->data=c;
		CreateBiTree(T->lchild);
		CreateBiTree(T->rchild);
	}
}

//先序递归遍历
void PreOrder(BiTree T){
	if(T!=NULL){
		printf("%c",T->data);
		PreOrder(T->lchild);
		PreOrder(T->rchild);
	}
}

//中序递归遍历
void InOrder(BiTree T){
	if(T!=NULL){
		InOrder(T->lchild);
		printf("%c",T->data);
		InOrder(T->rchild);
	}
}

//后序递归遍历
void PostOrder(BiTree T){
	if(T!=NULL){
		PostOrder(T->lchild);
		PostOrder(T->rchild);
		printf("%c",T->data);
	}
}




//第11题:对于元素值为x的节点,删除以它为根的子树----------未解决
void DeleteXTree(BiTree &T){
	if(T){
		DeleteXTree(T->lchild);
		DeleteXTree(T->rchild);
		free(T);
	}
}
void Search(BiTree &T,int x){
	x=x+48;
	BiTree p;
	SqQueue Q;
	InitQueue(Q);
	if(T){
		if(T->data==x){
			DeleteXTree(T);
			exit(0);
		}
	}
	EnQueue(Q,T);
	while(!isEmpty(Q)){
		DeQueue(Q,p);
		if(p->lchild){
			if(p->lchild->data==x){
				DeleteXTree(p->lchild);
				p->lchild=NULL;
			}
			else{
				EnQueue(Q,p->lchild);
			}
		}
		if(p->rchild){
			if(p->rchild->data==x){
				DeleteXTree(p->rchild);
				p->rchild=NULL;
			}
			else{
				EnQueue(Q,p->rchild);
			}
		}
	}
}

void Post(BiTree &T){
	SqStack s;							//初始化栈
	InitStack(s);						
	BiTree p=T,r;						//工作指针p和r
	while(p!=NULL||!StackEmpty(s)){
		if(p){
			Push(s,p);
			p=p->lchild;
		}
		else{
			GetTop(s,p);					//栈的基本方法,在此的作用是返回当前根节点
			if(p->rchild&&p->rchild!=r){	//如果右子树存在,且未被访问过
				p=p->rchild;				//转向右
				Push(s,p);					//进栈
				p=p->lchild;				//再走到最左
			}
			else{
				Pop(s,p);					//弹栈并访问
				printf("%c",p->data);
				r=p;					//记录最近访问的节点
				p=NULL;					//节点访问完后,重置p指针
			}
		}
	}
}

void main(){
	BiTree T;
	CreateBiTree(T);
	PostOrder(T);
	printf("\n");
	Post(T);
	printf("\n");
}
  • 8
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值