数据结构之---非递归中序遍历二叉树

二叉树中序非递归遍历算法实现

大家好,我是逝去的粒子,从今天起,我将尝试着数据结构从0开始学习分享,此篇文章作为试验,一方面可以为自己做笔记防止遗忘,另一方面希望可以帮助大家。不废话,正式开始。

1.第一步,我们需要先序递归创建二叉树,栈,以及栈的基础方法,因为上述这些不是今天的重点且网上有很多讲解,我就不重复造轮子了,代码如下:

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

//树的定义
typedef struct BiTNode{
	int data;
	struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;

//栈的定义
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;
}

//出栈
BiTree Pop(SqStack &s,BiTree 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);
	}
}

2.第二步:假设我们先序遍历输入:12#46###3#5##,(#表示空节点),如下创建了一个这样的二叉树:
在这里插入图片描述

3.第三步:递归先序遍历,简单来说就是始终坚持先左后中再右,代码如下:

//中序遍历--递归
void InOrder(BiTree T){
	if(T!=NULL){
		InOrder(T->lchild);
		printf("%c",T->data);
		InOrder(T->rchild);
	}
}
简单来说就是将树T的指针传过来,依次遍历,有的人传的是指针的地址,效果都一样

--------------------------------接下来就是今天的重点了:非递归中序-------------------------

4.第4步非递归中序遍历算法思想-->借助栈,先有一个工作指针p,让其从头节点依次扫描左节点,并将扫描到的节点依次进栈,如果扫描的左节点为空了时,从栈中弹出一个节点,此时显然弹出的这个节点及其他的左子树都已经被访问过了,我们再使用p继续访问此节点的右节点,将其进栈,然后继续右孩子节点的所有左孩子,不停的迭代,直到所有节点全部访问过,并且栈为空。根据此思想,编写如下代码:

//中序遍历--非递归
void InOrder2(BiTree T){
	SqStack s;
	InitStack(s);	//初始化栈
	BiTree p=T,a;		//遍历指针p
	while(p||!StackEmpty(s)){
		if(p){
			Push(s,p);
			p=p->lchild;
		}
		else{
			GetTop(s);	//在p出栈之前先查看
			a=Pop(s,p);		//出栈,a为接收出栈的p节点
			p=p->rchild;
		}
	}
}
1.首先初始化栈s,我用的是顺序栈,有能力的同学可以尝试着用链栈。
2.创建工作指是针p和a,其中p指向树T,也就是p指向节点13.进入循环(p不为空或者栈s不为空时)执行循环体:
	做判断:如果工作指针p不为空,此时p指向的节点1进栈,
	p继续指向左子树指向了节点2,
	继续将2进栈,由于节点2没有左子树,所以进入else语句,
	出栈之前输出节点值,那么此时输出的就是2,并将节点2弹出栈,
	再寻找节点2的右节点,进入if语句,就这样不断迭代。

好了,现在我们看似代码还是比较ok的,因为我本身小白,没办法,此时,运行试试看。
wa
果然没辜负我,又出错了,递归中序遍历能够正常实现,但非递归却只出现了一个数字2,再就没反应了,这是为什么。

5.第5步:调试阶段
为非递归这个函数添加一个断点,进行一步步调试,查看栈s以及p指针的变化。
在这里插入图片描述
直到有错误提示
在这里插入图片描述
此时我们发现了一个大问题,p指针的左右孩子都是为空,说明此时的p就是一个空指针,而且p的值为0x000000,有bug就解决,我发现,导致p错误的原因是当从栈中弹出一个节点时,我用的p指针已经不再是指向弹出那个节点的,而是指向了一个空节点,所以程序猜到else语句,对不对,那么原先写的p=p->lchild毫无疑问是错误的,此时,我想到用一个指针a来接收弹出的节点,然后将a赋给p,然后p代表当前弹出节点并继续访问其右节点。
如果有疑问的话,建议照着刚写的代码画着图实际演练一遍,或可以联系我。

//中序遍历--非递归
void InOrder2(BiTree T){
	SqStack s;
	InitStack(s);	//初始化栈
	BiTree p=T,a;		//遍历指针p
	while(p||!StackEmpty(s)){
		if(p){
			Push(s,p);
			p=p->lchild;
		}
		else{
			GetTop(s);	//在p出栈之前先查看
			a=Pop(s,p);		//出栈,a为接收出栈的p节点
			p=a;
			p=p->rchild;
		}
	}
}

在这里插入图片描述
成功解决,当遇到bug时,要学会去调试代码,当然调试的前提是你必须要手动的会描述一个算法过程。今天的试验分享就到这,后面会不定期分享我会的数据结构,第一次写的不好请见谅。

  • 29
    点赞
  • 118
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值