二叉树的遍历


前言

  T_T此专栏用于记录数据结构及算法的(痛苦)学习历程,便于日后复习(这种事情不要啊)。所用教材为《数据结构 C语言版 第2版》严蔚敏。


一、二叉树遍历的定义(官方版)

  根据二叉树的递归定义可知,二叉树是由3个基本单元组成:根结点、左子树和右子树。因此,若能依次遍历这三部分,便是遍历了整个二叉树。假如从 L、D、R 分别表示遍历左子树、访问根结点和遍历右子树,则有DLR、LDR、LRD、DRL、RDL、RLD这6种遍历二叉树的方案。若限定先左后右,则只有前3种情况,分别称之为先(根)序遍历、中(根)序遍历和后(根)序遍历。
  先序遍历二叉树的操作定义:若二叉树为空,则空操作;否则(1)访问根结点;(2)先序遍历左子树;(3)先序遍历右子树。
  中序遍历二叉树的操作定义:若二叉树为空,则空操作;否则(1)中序遍历左子树;(2)访问根结点;(3)中序遍历右子树。
  后序遍历二叉树的操作定义:若二叉树为空,则空操作;否则(1)后序遍历左子树;(2)后序遍历右子树;(3)访问根结点。

二、二叉树遍历的定义(胡乱理解版)

  先序遍历二叉树:根据每个结点第一次访问到(我来了)的次序访问结点。
  中序遍历二叉树:根据每个结点第二次访问到(我又来了)的次序访问结点。
  后序遍历二叉树:根据每个结点第三次访问到(我又又来了)的次序访问结点。

三、二叉树遍历的递归实现

//先序遍历
status PreOrderTraverse(BiTree T)
{
	if (T == NULL)return ok;
	VisitT(T);					//希望对每个结点进行的操作
	PreOrderTraverse(T->lchild);
	PreOrderTraverse(T->rchild);
}
//中序遍历
status InOrderTraverse(BiTree T)
{
	if (T == NULL)return ok;
	InOrderTraverse(T->lchild);
	VisitT(T);					//希望对每个结点进行的操作
	InOrderTraverse(T->rchild);
}
//后序遍历
status PostOrderTraverse(BiTree T)
{
	if (T == NULL)return ok;
	PostOrderTraverse(T->lchild);
	PostOrderTraverse(T->rchild);
	VisitT(T);					//希望对每个结点进行的操作
}

四、二叉树遍历的非递归实现

  二叉树遍历的递归实现虽然语句简单,但难以理解,且当结点数量较多时,递归会占用大量内存空间。为此,我们需要了解二叉树遍历的非递归实现。
  下面给出中序遍历的非递归实现代码。有关栈的操作见栈的实现。注意栈的结点数据域类型应为BiTreeBTNode*

void InOrderTraverse_unrec(BiTree T)
{
	SqStack S;
	CreatStack(S);   //创建空栈
	BiTree p = T;
	while (p || !Stackempty(S))   //如果p和栈都空则终止循环
	{
		if (p) 
		{
			//栈顶元素始终是p的parent节点
			Push(S, p);   //入栈
			p = p->lchild;
		}
		else 
		{
			Pop(S, p); //出栈,把栈顶元素弹出给p,此时变成了原p的parent
			//此时p的左孩子为空,根据in-oder规则,输出根节点p,然后再以相同的方式遍历他的右孩子
			printf("%c", p->data);
			p = p->rchild; //输出根节点后,遍历其右子树
		}
	}
}

五、二叉树层次遍历的非递归实现

  除了先中后序三种遍历方式,有时我们还使用层次遍历的方式遍历二叉树。这种方式按照 “从上到下,从左到右" 的顺序遍历二叉树, 即先遍历二叉树第一层的结点,然后是第二层的结点,直到最底层的结点, 对每一层的遍历按照从左到右的次序进行。层次遍历不是一个递归过程,其算法的实现可以借助队列这种数据结构。
  下面给出具体实现代码。有关队列的操作见队列的实现。注意队列的结点数据域类型应为BiTreeBTNode*

void LevelOrder(BiTree T)
{
	BiTree p;
	SqQueue qu;   
	CreatQueue(qu);   //创建空队
	EntryQ(qu, T);    //将根节点入队
	while (!Queueempty(qu))   //如果队列空则停止循环
	{
		OutQ(qu, p);      //出队一个结点
		printf("%c ", p->data);    //输出
		if(p->lchild != NULL)EntryQ(qu, p->lchild);  //入队左孩子
		if(p->rchild != NULL)EntryQ(qu, p->rchild);  //入队右孩子
	}
}

总结

  路漫漫其修远兮,吾将上下而摆烂。(又是划水的一天,water,water,water,water,water…)
  有任何疑问和补充,欢迎交流。(但我显然不会T_T)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值