高级数据结构与算法——二叉树的四种遍历算法(含非递归)

二叉树的遍历定义

  所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,是二叉树上进行其它运算之基础。
  其中搜索路线我们这里介绍4中:前序遍历,中序遍历,后续遍历,层次遍历。

前序遍历

若二叉树非空,则依次执行如下操作:
⑴ 访问根结点;
⑵ 遍历左子树;
⑶ 遍历右子树
在这里插入图片描述
该二叉树遍历结果为:G D A F E M H Z

递归算法

//定义结构体下面通用
typedef struct BTNode
{
	Elemtype data;
	BTNode *lchild;
	BTNode *rchild;
}BTNode;
/*
递归遍历算法写起来比较简单根据前序遍历步骤即可
*/
void PreOrder(BTNode *p)
{
	if(p != NULL)
	{
		cout<<p->data<<" ";
		PreOrder(p->lchild);
		PreOrder(p->rchild);
	}
}

非归算法

void NicePreOrder(BTNode *p)
{
	if(p == NULL) return;
	stack<BTNode *>st;
	st.push(p);
	while(!st.empty())
	{
		p = st.top();
		st.pop();
		cout<<p->data<<" ";
		if(p->rchild != NULL)
			st.push(p->rchild);
		if(p->lchild != NULL)
			st.push(p->lchild);
	}
}

中序遍历

若二叉树非空,则依次执行如下操作:
⑴ 遍历左子树;
⑵ 访问根结点;
⑶ 遍历右子树
在这里插入图片描述
该二叉树遍历结果为:A D E F G H M Z

递归算法

/*
递归遍历算法写起来比较简单根据中序遍历步骤即可
*/
void InOrder(BTNode *p)
{
	if(p!= NULL)
	{
		PreOrder(p->lchild);
		cout<<p->data<<" ";
		PreOrder(p->rchild);
	}
}

非递归算法

/*该算法核心思想就是先一路向左将所有结点压栈,
最后判断当前结点其是否有右孩子有的话就压栈没
有则取栈顶元素打印并且弹出。*/
void NiceInOrder(BTNode *p)
{
	if(p == NULL) return;
	stack<BTNode *>st;
	while(p != NULL || !st.empty())
	{
		while(p != NULL)
		{
			st.push(p);
			p = p->lchild;
		}
		p = st.top();
		st.pop();
		cout<<p->data<<" ";
		p = p->rchild;
	}	
}

后序遍历

若二叉树非空,则依次执行如下操作:
⑴ 遍历左子树;
⑵ 遍历右子树;
⑶ 访问根结点
在这里插入图片描述
该二叉树遍历结果为:A E F D H Z M G

递归算法

/*
递归遍历算法写起来比较简单根据后序遍历步骤即可
*/
void PastOrder(BTNode *p)
{
	if(p!= NULL)
	{
		PreOrder(p->lchild);
		PreOrder(p->rchild);
		cout<<p->data<<" ";
	}
}

非递归算法(两个栈)

/*因为后序遍历的根节点在最后访问,所以需要用两个栈来实现
stRes用来存储结果最终将里面的所有元素打印,值得注意的是
因为我们用到了两个栈,所以先将左孩子压栈,再压右孩子,这
样就使得压入stRes中时先压右再压左,打印的时候也就符合后
序遍历的规则了*/
void NicePastOrder(BTNode *p)
{
	if(p == NULL) return;
	stack<BTNode *>st;
	stack<BTNode *>stRes;
	st.push(p);
	while(!st.empty())
	{
		p = st.top();
		st.pop();
		stRes.push(p);
		if(p->lchild != NULL)
			st.push(p->lchild);
		if(p->rchild != NULL)
			st.push(p->rchild);
	}
	while(!stRes.empty())
	{
		p = stRes.top();
		cout<<p->data<<" ";
		stRes.pop();
	}
}

非递归算法(带标志位的一个栈)

/*
只使用一个栈便可以达到后序非递归遍历大大节省了内存消耗,因为后序
遍历是先左再右再根,所以我们需要知道右孩子什么时候被打印,接下来
才可以打印根结点。其中我们设置标志位为tag,将每次打印后的结点设
置为标志位,用以判断p->rchild是否和tag相等来选择是否该打印此时
的根节点。
*/
void NicePastOrder2(BTNode *p)
{
	if(p == NULL) return;
	stack<BTNode *>st;

	BTNode *tag = NULL;

	while(p != NULL || !st.empty())
	{
		while(p != NULL)
		{
			st.push(p);
			p = p->lchild;
		}
		
		p = st.top();
		st.pop();
		if(p->rchild == NULL || p->rchild == tag)
		{
			cout<<p->data<<" ";
			tag = p;
			p = NULL;
		}
		else
		{
			st.push(p);
			p = p->rchild;
		}
	}
}

层次遍历

若二叉树非空,则依次执行如下操作:
  逐层,从左向右访问节点
在这里插入图片描述
该二叉树遍历结果为:G D M A F H Z E

递归算法

/*
层次遍历的递归采用的是广度优先遍历,我们在LevelOrder中进行递归调用
当层数为0时打印,再在levelOrder中将每层最终结果打印
*/
void LevelOrder(BTNode *p,int level)
{
	if(p == NULL) return;

	if(level == 0)
		cout<<p->data<<" ";
	LevelOrder(p->lchild,level-1);
	LevelOrder(p->rchild,level-1);
	
}
void levelOrder(BTNode *p,int level)
{
	for(int i=0 ;i<=level; i++)
		LevelOrder(p,i);
}

非递归算法

/*
非递归层序遍历比较简单,我们利用队列的性质即可,先将左孩子入队,
再将右孩子入队,然后进行打印
*/
void NiceLevelOrder(BTNode *p)
{
	if(p == NULL) return;
	queue<BTNode *>qu;
	qu.push(p);
	while(!qu.empty())
	{
		p = qu.front();
		cout<<p->data<<" ";
		qu.pop();
		if(p->lchild != NULL)
			qu.push(p->lchild);
		if(p->rchild != NULL)
			qu.push(p->rchild);
	}
}
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值