二叉树遍历(前、中、后)

https://www.cnblogs.com/nancymake/p/6516933.html
在这里插入图片描述
在这里插入图片描述
先讲解图中几种遍历:
其实每种遍历的规则都是针对于节点来说,即每个节点需要满足相应的规则。
先序遍历:
顺序为根、左、右,则每个节点需满足此条件。从整体来看,毫无疑问A是根节点,那么之后是左边B,我们需要将B所有后代遍历完整体才是左,那么对于B则又需要遵从此规则,即B、D、E,而因为此时E有子节点,那么对于E而言,则是E、H,所以根、左边遍历完成是A、B、D、E、H,那么右边也是同样道理,根、左、右,C、F、G,因为F有子节点,对于F而言,就是F、I,所以右边完成后是C、F、I、G。总的就是A、B、D、E、H、C、F、I、G。
中序遍历:
顺序为左、根、右,则每个节点需满足此条件。从整体来看,最左边为D,那么根据顺序左、根、右,即D、B、E,因为E有子节点,那么对于E而言,则是H、E。所以左边遍历完成即为D、B、H、E,当然过后是A。现在到右边,也是满足顺序左、根、右,即F、C、G,因为F有子节点,对于F而言,就是F、I,所以左边完成后是F、I、C、G。总就是D、B、H、E、A、F、I、C、G。
后序遍历:
顺序为左、右、根,则每个节点需满足此条件。最左边为D,那么根据顺序左、右、根,即D、E、B,因为E有子节点,那么对于E而言,则是H、E。所以左边遍历完成即为D、H、E、B。现在到右边,也是满足顺序左、右、根,即F、G、C,因为F有子节点,对于F而言,就是I、F,所以左边完成后是I、F、G、C。当然最后是A。总就是D、H、E、B、I、F、G、C、A。

其实上面仅仅是自己理解的方法,也有不同的理解,我们也可以从下往上看。这里就不再赘述。
对于实现来说,我们怎么用代码描述这样的一种数据结构,这值得思考。
我们可以分析,其实就是让结点之间产生一种关联,每个节点就是一个数据,只不过需要用指针来记录节点间的关系以及联系。
代码如下:


#include "pch.h"
#include <iostream>

#include <stdio.h>
#include <string.h>

#define TElemType char

int top = -1;			// top变量时刻表示栈顶元素所在位置

// 定义结点类型
typedef struct BiTNode {
	TElemType data;		// 数据域
	struct BiTNode *lchild, *rchild;		// 左右孩子指针
}BiTNode, *BiTree;

// 构造一棵二叉树
void CreateBiTree(BiTree *T)
{
	*T = (BiTNode*)malloc(sizeof(BiTNode));	  // 根结点
	(*T)->data = 'A';	
	(*T)->lchild = (BiTNode*)malloc(sizeof(BiTNode));  // 左指针
	(*T)->rchild = (BiTNode*)malloc(sizeof(BiTNode));  // 右指针
	(*T)->lchild->data = 'B';
	(*T)->lchild->lchild= (BiTNode*)malloc(sizeof(BiTNode));
	(*T)->lchild->rchild = (BiTNode*)malloc(sizeof(BiTNode));
	(*T)->lchild->rchild->data = 'C';
	(*T)->lchild->rchild->lchild = NULL;
	(*T)->lchild->rchild->rchild = NULL;
	(*T)->rchild->data = 'D';
	(*T)->rchild->lchild = (BiTNode*)malloc(sizeof(BiTNode));
	(*T)->rchild->lchild->data = 'E';
	(*T)->rchild->lchild->lchild = NULL;
	(*T)->rchild->lchild->rchild = NULL;
	(*T)->rchild->rchild = (BiTNode*)malloc(sizeof(BiTNode));
	(*T)->rchild->rchild->data = 'F';
	(*T)->rchild->rchild->lchild = NULL;
	(*T)->rchild->rchild->rchild = NULL;
	(*T)->lchild->lchild->data = 'G';
	(*T)->lchild->lchild->rchild = NULL;
	(*T)->lchild->lchild->lchild = NULL;
}

// 前序和中序遍历使用进栈函数
void Push(BiTNode **a, BiTNode *elem) {
	a[++top] = elem;
}

// 出栈
void Pop() {
	if (top == -1)
		return;
	top--;
}

// 输出结点本身数据
void PrintElem(BiTNode *elem) {
	printf("%c  ", elem->data);
}

// 获取栈顶元素
BiTNode *GetTop(BiTNode **a)
{
	return a[top];
}

// 先序遍历递归算法
void PreOrderTraverse(BiTree tree)
{
	BiTNode *a[20];
	BiTNode *p;
	Push(a, tree);
	while (top != -1) {
		p = GetTop(a);
		Pop();
		while (p) {
			PrintElem(p);
			if (p->rchild)  //如果该结点有右孩子,右孩子进栈
				Push(a, p->rchild);
			p = p->lchild;
		}		
	}
}


// 中序遍历递归算法
void InOrderTraverse(BiTree tree)
{
	BiTNode *a[20];		// 定义一个顺序栈
	BiTNode *p;  // 临时指针
	Push(a, tree);  // 根结点进栈
	while (top != -1)		// top !=-1说明栈内不为空,程序继续执行
	{
		while ((p = GetTop(a)) && p)		// 取栈顶元素,且不能为NULL
		{
			Push(a, p->lchild);		//将该结点的左孩子进栈,如果没有左孩子,NULL进栈
		}
		Pop();		// 跳出循环,栈顶元素肯定为NULL,将NULL弹栈
		if (top != -1) {
			p = GetTop(a);		//取栈顶元素
			Pop();
			PrintElem(p);
			Push(a, p->rchild);  // 将p指向结点的右孩子进栈
		}

	}
}

///

// 后序遍历非递归算法
typedef struct SNode {
	BiTree p;
	int tag;
}SNode;

// 后序遍历使用进栈函数
void postpush(SNode *a, SNode sdata) {
	a[++top] = sdata;
}

//后序遍历
void  PostOrderTraverse(BiTree Tree) {
	SNode a[29];
	BiTNode *p;
	int tag;
	SNode sdata;
	p = Tree;

	while (p || top != -1)
	{
		while (p) {
			sdata.p = p;
			sdata.tag = 0;	// 由于遍历是左孩子,设置标志位为0
			postpush(a, sdata);		// 入栈 
			p = p->lchild;		// 以该 结点为根结点,遍历左孩子
		}
		sdata = a[top];
		Pop();
		p = sdata.p;
		tag = sdata.tag;

		if (tag == 0)		// tag==0 说明该 结点还没有遍历它的右孩子
		{
			sdata.p = p;
			sdata.tag = 1;
			postpush(a, sdata);		// 更改结点标志位,重新入栈
			p = p->rchild;		// 该结点右孩子为根结点,重新循环
		}
		else
		{
			PrintElem(p);
			p = NULL;
		}
	}
}

int main()
{
	BiTree Tree;
	CreateBiTree(&Tree);

	printf("二叉树前序遍历结果为(DLR):\n");
	PreOrderTraverse(Tree);

	printf("\n二叉树中序遍历结果为(LDR):\n");
	InOrderTraverse(Tree);

	printf("\n二叉树后序遍历结果为(LRD):\n");
	PostOrderTraverse(Tree);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值