二叉树的前序、中序、后序遍历(递归、非递归方式)以及层次遍历实现

 二叉树使用的案例如下:

#include<stdio.h>
#include<stdlib.h>

// 函数状态代码
#define TRUE 1 // 逻辑1
#define FALSE 0 // 逻辑0
#define OK 1 // 程序运行无误
#define ERROR 0 // 程序运行有误
#define INFEASIBLE -1
#define OVERFLOW -2 // 结果溢出
typedef int Status; // 函数状态类型:int
typedef int boolean; // 布尔类型:int

// 二叉结点数据元素类型
typedef int TreeElem; // 二叉结点数据元素类型:int

// 二叉树存储结构
typedef struct BiNode
{
	TreeElem data; // 数据域
	struct BiNode *lchild, *rchild; // 左右孩子指针域
}BiNode, *BiTree;

// 辅助数据结构结点数据元素类型
typedef BiNode* AElem; // 辅助数据结构数据元素类型:二叉结点指针

// 辅助栈存储结构
typedef struct SNode
{
	AElem data; // 数据域
	struct SNode *next; // 指针域
}SNode, *linkStack;

// 辅助队列存储结构
typedef struct QNode 
{// 队列结点
	AElem data; // 数据域
	struct QNode *next; // 指针域
}QNode;
typedef struct
{// 队列
	QNode *front, *rear; // 队首队尾指针
}linkQueue;

// -----辅助栈操作描述-----
Status InitStack(linkStack *S)
{// 初始化栈S
	SNode *s; // 工作指针
	s = (SNode*)malloc(sizeof(SNode)); // 新建表头结点
	s->data = NULL; // 数据域赋初值
	s->next = NULL; // 指针域赋初值
	*S = s; // 栈指针指向此新建结点
	return OK;
}// InitStack()

boolean StackIsEmpty(linkStack S)
{// 判断栈S是否为空
	if(S->next==NULL)
		return TRUE;
	return FALSE;
}// StackIsEmpty()

Status DisplayStack(linkStack S)
{// 可视化输出链栈S
 /*
	使用遍历指针p依次输出从栈顶到栈底的所有元素	
 */
	SNode *p=S->next; // 遍历指针
	while(p!=NULL) // p非空时
	{
		visit(p->data); // 访问数据域
		printf("\n");
		p = p->next; // 继续遍历
	}// while
	return OK;
}// DisplayStack()

Status GetTop(linkStack S, AElem *x)
{// 获取栈顶元素并使用x返回
	if(S->next==NULL) // 栈为空
		return ERROR;
	else
		*x = S->next->data;
	return OK;
}// GetTop()

Status Push(linkStack S, AElem x)
{// 将数据元素x入栈
 /*
	基本思想:新建结点按头插法插入链栈中
 */
	SNode *s; // 工作指针
	s = (SNode*)malloc(sizeof(SNode)); // 新建结点
	s->data = x; // 数据域赋值
	s->next = S->next; // 完善指针域
	S->next = s;
	return OK;
}// Push()

Status Pop(linkStack S, AElem *x)
{// 弹栈并使用x接收弹出结点的数据域值
 /*
	基本思想:首先接收栈顶元素值并判断是否可弹栈,若可弹栈,删除栈顶结点。
 */
	SNode *s=S->next; // 工作指针
	if(!(GetTop(S, x))) // 无法获取栈顶元素说明栈为空,此时无法弹栈
		return ERROR;
	S->next = s->next; // 逻辑删除
	free(s); // 物理删除
	return OK;
}// Pop()

// -----辅助队列操作描述-----
Status InitQueue(linkQueue *Q)
{// 初始化链队列Q
 /*
	基本思想:建立表头结点,并使队首队尾指针均指向此结点
	*/
	QNode *s; // 工作指针
	s = (QNode*)malloc(sizeof(QNode)); // 新建表头结点
	s->data = NULL; // 初始化数据域
	s->next = NULL; // 初始化指针域
	Q->front = s; // 队首指针指向此新建结点
	Q->rear = s; // 队尾指针指向新建结点
	return OK;
}// InitQueue()

boolean QueueIsEmpty(linkQueue Q)
{// 判断队列是否为空
	if(Q.front==Q.rear)
		return TRUE;
	return FALSE;
}// QueueIsEmpty()

Status QueueDisplay(linkQueue Q)
{// 可视化输出队列Q
	QNode *p=Q.front->next; // 遍历指针
	while(p!=NULL)
	{
		visit(p->data);
		p = p->next;
	}// while
	printf("\n");
	return OK;
}// QueueDisplay()

Status GetHead(linkQueue Q, AElem *x)
{// 获取队列Q队首元素并使用x返回
	if(QueueIsEmpty(Q)) // 队列为空
		return ERROR;
	*x = Q.front->next->data;
	return OK;
}// GetHead()

Status EnQueue(linkQueue *Q, AElem x)
{// 将数据元素x入队
 // 基本思想:首先新建结点,然后按尾插法插入新结点
	QNode *s; // 工作指针
	s = (QNode*)malloc(sizeof(QNode)); // 新建结点
	s->data = x; // 数据域赋值
	s->next = Q->rear->next;
	Q->rear->next = s;
	Q->rear = s;
	return OK;
}// EnQueue()

Status DeQueue(linkQueue *Q, AElem *x)
{// 队首元素出队并使用x返回
	QNode *s=Q->front->next; // 工作指针
	if(!(GetHead(*Q, x))) // 获取队首元素
		return ERROR;
	Q->front->next = s->next; // 逻辑删除
	if(s==Q->rear) // 若队列只含一个元素
		Q->rear = Q->front;
	free(s); // 物理删除
	return OK;
}// DeQueue()

// 二叉树操作描述
Status visit(BiNode *s)
{// 访问二叉指针s指向的二叉结点
	printf("%d ", s->data); // 输出结点数据域
	return OK;
}// visit

Status Example(BiTree *T)
{// 将案例加载到二叉树T
	BiNode *s, *p, *q; // 工作指针

	s = (BiNode*)malloc(sizeof(BiNode)); // 新建结点
	s->data = 1; // 数据域赋值
	s->lchild = NULL; // 指针域赋初值
	s->rchild = NULL;
	*T = s; // 将此结点作为根结点

	p = s; // p指向数据元素为1结点

	s = (BiNode*)malloc(sizeof(BiNode)); // 新建结点
	s->data = 2; // 数据域赋值
	s->lchild = NULL; // 指针域赋初值
	s->rchild = NULL;
	p->lchild = s;

	s = (BiNode*)malloc(sizeof(BiNode)); // 新建结点
	s->data = 3; // 数据域赋值
	s->lchild = NULL; // 指针域赋初值
	s->rchild = NULL;
	p->rchild = s;
	
	q = p->rchild; // q指向数据元素为3结点
	p = p->lchild; // p指向数据元素为2结点

	s = (BiNode*)malloc(sizeof(BiNode)); // 新建结点
	s->data = 4; // 数据域赋值
	s->lchild = NULL; // 指针域赋初值
	s->rchild = NULL;
	p->lchild = s;

	s = (BiNode*)malloc(sizeof(BiNode)); // 新建结点
	s->data = 5; // 数据域赋值
	s->lchild = NULL; // 指针域赋初值
	s->rchild = NULL;
	p->rchild = s;

	q = p->rchild; // q指向数据元素为5结点

	s = (BiNode*)malloc(sizeof(BiNode)); // 新建结点
	s->data = 6; // 数据域赋值
	s->lchild = NULL; // 指针域赋初值
	s->rchild = NULL;
	q->lchild = s;

	return OK;
}// Example()

Status PreOrder_re(BiTree T)
{// 递归方式先序遍历二叉树T
	if(T!=NULL)
	{
		visit(T); // 访问根结点
		PreOrder_re(T->lchild); // 先序遍历左子树
		PreOrder_re(T->rchild); // 先序遍历右子树
	}// if
	return OK;
}// PreOrder_re

Status InOrder_nr(BiTree T)
{// 非递归中序遍历二叉树T
 /*
	基本思想:使用一辅助栈存储已由遍历指针指向但未输出的二叉结点。在遍历指针非空或
	辅助栈非空时进行如下循环:当遍历指针非空时,将其指向的二叉结点入栈,并继续向左
	下进发;当遍历指针为空,弹栈并输出,遍历指针向弹栈结点右下进发。
	*/
	linkStack S; // 辅助栈
	BiNode *p=T, *s; // 二叉树的遍历指针
	InitStack(&S); // 初始化辅助栈

	while(p!=NULL||(!StackIsEmpty(S))) // 遍历指针非空或栈非空时
	{
		if(p!=NULL) // 遍历指针非空
		{
			Push(S, p); // p结点入栈
			p = p->lchild; // 向左下进发
		}// if
		else // 遍历指针为空
		{
			Pop(S, &s); // 弹栈
			visit(s); // 访问
			p = s->rchild; // 向弹栈结点的右下进发
		}// else
	}// while
	printf("\n");

	return OK;
}// InOrder_nr

Status PreOrder_nr(BiTree T)
{// 先序非递归遍历二叉树T
 /*
	基本思想:使用辅助栈存储已输出但左右子树均为输出的二叉结点指针,使用一指针遍历二叉树的结点。
	在遍历指针非空或栈非空的情况下进行如下循环:若遍历指针非空,输出指针指向的二叉结点数据域,
	并使此结点指针入栈,接着遍历指针向左下进发;若遍历指针为空,弹栈并使遍历指针向弹栈结点右下进发。
	*/
	linkStack S; // 辅助栈
	BiNode *p=T; // 二叉树的遍历指针
	BiNode *s; // 工作指针

	InitStack(&S); // 初始化辅助栈
	while(p!=NULL||!(StackIsEmpty(S))) // p非空或栈非空时
	{
		if(p!=NULL) // 遍历指针非空
		{
			visit(p); // 访问结点
			Push(S, p); // p结点入栈
			p = p->lchild; // 向左下进发
		}// if
		else // 遍历指针空
		{
			Pop(S, &s);
			p = s->rchild;
		}// else
	}// while
	printf("\n");

	return OK;
}// PreOrder_nr()

Status PostOrder_nr(BiTree T)
{// 后序非递归遍历二叉树T
 /*
	基本思想:使用辅助栈存储左右子树均未输出的二叉结点指针,使用指针p遍历二叉树,使用指针pre指向上一次输出的结点,
	默认情况下,指针pre指向NULL。在指针p非空或栈非空情况下,进行如下循环:若指针p非空,说明遍历到了新的未输出结点,
	将此结点入栈,并继续向左下进发;若指针p为空,首先获取栈顶元素,并判断栈顶元素右孩子是否与pre指向的结点相同,若
	相同,弹栈并输出栈顶元素,重新设置pre;若不同,向栈顶元素右下进发。
	*/
	linkStack S; // 辅助栈
	BiNode *p=T; // 遍历指针
	BiNode *pre=NULL; // 指向上次输出的结点
	BiNode *s; // 工作指针

	InitStack(&S); // 初始化工作栈
	while(p!=NULL||(!StackIsEmpty(S))) // 当指针p非空或栈非空时
	{
		if(p!=NULL) // 指针p非空
		{
			Push(S, p); // 将此结点入栈
			p = p->lchild; // 向左下进发
		}// if
		else 
		{
			GetTop(S, &s); // 获取栈顶元素
			if(s->rchild==NULL||s->rchild==pre) // 栈顶元素的右孩子刚刚被访问过或无右孩子
			{
				Pop(S, &s); // 弹栈
				visit(s); // 访问结点
				pre = s;
			}// if
			else
			{
				p = s->rchild; // 向栈顶元素右下进发
			}// else
		}// else
	}// while
	printf("\n");
	return OK;
}// PostOrder_nr

Status LevelOrder(BiTree T)
{// 层次遍历二叉树T
 // 基本思想:使用辅助队列,首先将根结点入队,出队并输出队首元素,并将出队元素的左右孩子依次入队,直到队列为空。
	linkQueue Q; // 辅助队列
	AElem x; // 存储出队元素

	InitQueue(&Q); // 初始化队列
	EnQueue(&Q, T); // 根结点入队
	while(!(QueueIsEmpty(Q))) // 当队列非空时
	{
		DeQueue(&Q, &x); // 出队
		visit(x); // 访问出队元素
		if(x->lchild!=NULL) // 左孩子入队
			EnQueue(&Q, x->lchild);
		if(x->rchild!=NULL) // 右孩子入队
			EnQueue(&Q, x->rchild);
	}// while
	printf("\n");
	return OK;
}// LevelOrder()

// 主函数
void main()
{
	BiTree T;
	if(Example(&T))
		printf("二叉树案例已加载!\n");
	LevelOrder(T);
}

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值