【代码 C/C++】二叉树前序,中序,后序遍历(递归、非递归)

本文在由层次遍历构造二叉树的基础上写的

正式开始打代码前的一些小知识

putchar()函数

int putchar(int char)

把参数 char 指定的字符(一个无符号字符)写入到标准输出 stdout 中。
函数以无符号 char 强制转换为 int 的形式返回写入的字符,如果发生错误则返回 EOF。

非递归

三种遍历的非递归形式需要借助栈来实现。

代码部分

结构体

//二叉树的数据结构
typedef struct BiTNode{
	BiElemType Bidata;
	struct BiTNode* lchild;
	struct BiTNode* rchild;
}BiTNode, *BiTree;

//栈的数据结构
typedef struct {
	ElemType data[MaxSize];
	int top;
}SqStack;

前序遍历(递归、非递归)

//前序遍历(递归实现):根左右
void PreOrder(BiTree p)
{
	if (p != NULL)
	{
		putchar(p->Bidata);
		PreOrder(p->lchild);
		PreOrder(p->rchild);
	}
}

//前序遍历(非递归实现)
void PreOrder_non_Recrusive(BiTree T)
{
	BiTree p = T;//p用于指向当前遍历到的结点
	SqStack s;//新建栈
	InitStack(s);//初始化栈
	while (p || !IsEmpty(s))
	{
		if (p)//如果p不为NULL,输出p的data,继续寻找p的左子树,直到找到最左下的结点
		{
			putchar(p->Bidata);
			Push(s, p);
			p = p->lchild;
		}
		else
		{
			Pop(s, p);
			p = p->rchild;
		}
	}
}

中序遍历(递归、非递归)


//中序遍历(递归实现):左根右
void InOrder(BiTree p)
{
	if (p != NULL)
	{
		InOrder(p->lchild);
		putchar(p->Bidata);
		InOrder(p->rchild);
	}
}

//中序遍历(非递归实现)
void InOrder_non_Recrusive(BiTree T)
{
	BiTree p = T;
	SqStack s;
	InitStack(s);
	while (p || !IsEmpty(s))
	{
		if (p)
		{
			Push(s, p);
			p = p->lchild;
		}
		else
		{
			Pop(s, p);
			putchar(p->Bidata);
			p = p->rchild;
		}
	}
}

后序遍历(递归、非递归)

//后序遍历(递归实现):左右根
void PostOrder(BiTree p)
{
	if (p != NULL)
	{
		PostOrder(p->lchild);
		PostOrder(p->rchild);
		putchar(p->Bidata);
	}
}

//后序遍历(非递归实现)
//由于后序遍历是左右根,需要记录上一个被访问结点才能先输出其右子树的数据,比前序和中序复杂一点
void PostOrder_non_Recrusive(BiTree T)
{
	BiTree p = T;
	BiTree pre = T;//pre用于记录上一个被访问(Pop弹出)的结点
	SqStack s;
	InitStack(s);
	while (p || !IsEmpty(s))
	{
		if (p && pre != p->lchild && pre != p->rchild)
		{
			Push(s, p);
			p = p->lchild;
		}
		else
		{	
			if (p && pre != p->rchild)
			{
				p = p->rchild;
			}
			else
			{
				Pop(s, p);
				//printf("%d", IsEmpty(s));
				putchar(p->Bidata);
				pre = p;
				GetTop(s, p);
			}
			
		}
	}
}

打代码过程遇到的困难

关于对头文件xxx.h(这里是function.h)的引用问题(很初级很基础的问题)

我现在有一个头文件和两个cpp文件,分别是

function.h
main.cpp
stack.cpp

写代码的时候,我把所有的函数都写进了function.h,认为这样可以让cpp文件更加简洁,如下

function.h

//函数定义与实现
//前序遍历(递归实现):根左右
void PreOrder(BiTree p)
{
	......
}

//中序遍历(递归实现):左根右
void InOrder(BiTree p)
{
......
}

//栈
void InitStack(SqStack& S);
bool IsEmpty(SqStack S);
......
main.cpp

#include"function.h"

int main()
{
	//如前序遍历,中序遍历等操作
	......
}
stack.cpp

#include"function.h"

//一些栈相关函数实现
/初始化栈
void InitStack(SqStack& S)
{
	......
}

//判断栈是否为空
bool IsEmpty(SqStack S)
{
	......
}
......

然后出现了报错,是说void InOrder(BiTree p)等函数已经在main.obj中定义过,在stack.obj中出现了重复定义。
于是我了解了一下头文件与cpp文件的关系:
简单说来(是很朴素的理解方法,并不专业),在main.cpp文件中输入#include"function.h"以后,就相当于把function.h中的代码往main.cpp中复制了一份,而我在stack.cpp中同样写了#include"function.h",因此对于在function.h中定义并实现的void InOrder(BiTree p)等函数,分别在main.obj和stack.obj都实现了,造成重复。
而function.h中对栈相关函数void InitStack(SqStack& S)等仅定义并未实现,因此没有报错。

关于栈的GetTop()函数问题

之前学习后我写的GetTop()函数如下

bool GetTop(SqStack S, ElemType& e)
{
	if (IsEmpty(S))
	{
		return false;
	}
	e = S.data[S.top];
	return true;
}

而这在后序遍历(非递归)函数中出了问题。后序遍历代码中有这样一句

//s是非递归时用到的栈,p是当前栈顶元素
GetTop(s, p);

当栈空时GetTop()函数返回FALSE,但不会对e赋值,这就导致p一直等于最后一个出栈的元素,从而造成无限循环。改成以下即可

bool GetTop(SqStack S, ElemType& e)
{
	if (IsEmpty(S))
	{
		e = NULL;
		return false;
	}
	e = S.data[S.top];
	return true;
}

我想了一下,其实本来就应该有e = NULL;这一句,但之前的代码并没有因此出现什么问题,所以一直没有注意过这一点。

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值