《算法笔记》读书记录DAY_31

本文详细介绍了二叉树的四种遍历方式:先序遍历、中序遍历、后序遍历和层序遍历。通过递归实现,先序遍历顺序为根-左-右,中序遍历顺序为左-根-右,后序遍历顺序为左-右-根。层序遍历则采用广度优先搜索,按层次从左到右访问节点。每种遍历方式都提供了相应的递归代码实现。
摘要由CSDN通过智能技术生成

CHAPTER_9  提高篇(3)——数据结构(2)

这节我们讲解二叉树的遍历。二叉树的遍历是指通过一定顺序访问二叉树的所有结点。遍历方法有四种:先序遍历、中序遍历、后序遍历、层序遍历。下面分别介绍这四种遍历。

9.2.1 先序遍历

先序遍历采用递归的方式进行,首先要将树分为三个部分:根节点、左子树、右子树。对于先序遍历来说,总是先访问根节点,然后访问左子树,最后访问右子树。访问左子树和右子树的过程是一个递归的过程,例如访问左子树时,同样要访问它的根节点,然后访问它的左子树,最后访问它的右子树。访问右子树的过程也同样。

对于上图这个例子,先序遍历的过程如下:1 2 4 6 7 3 5 。

为了实现递归的先序遍历,我们需要两样东西:递归式和递归边界。其中递归式已经由定义得到,即按照根节点、左子树、右子树的顺序访问。那么递归的边界是什么呢?从上个例子可以发现,递归边界是二叉树和为一个空树。即访问子树时,发现子树为空,那么可以停止子树的访问而继续后面的访问。

由此可以给出递归的先序遍历代码:

void preorder(node* root) {
	if(root==NULL)             //到达递归边界,回退 
		return;
	cout<<root->data<<endl;    //访问根节点 
	preorder(root->lchild);    //访问左子树 
	preorder(root->rchild);    //访问右子树 
}

9.2.2 中序遍历

中序遍历采用递归的方式进行,它总是先访问左子树,然后访问根节点,最后访问右子树。同样地,访问左子树和右子树的过程是递归进行的。例如访问左子树时,先访问它的左子树,再访问它的根节点,最后访问它的右子树。递归的过程中,若子树为空,则停止子树的访问进行后续的遍历。

对于上图例子,中序遍历的结果为:4 6 7 2 1 5 3 。

中序遍历的递归实现思路与先序遍历相同,只是左子树和根节点的访问顺序交换了,递归代码如下:

void preorder(node* root) {
	if(root==NULL)             //到达递归边界,回退 
		return;
	preorder(root->lchild);    //访问左子树 
	cout<<root->data<<endl;    //访问根节点 
	preorder(root->rchild);    //访问右子树 
}

9.2.3 后序遍历

后序遍历也采用递归的方式进行,它总是先访问左子树,然后访问右子树,最后访问根节点。同样地,访问左子树和右子树的过程是递归进行的。例如访问左子树时,先访问它的左子树,再访问它的右子树,最后访问它的根节点。递归的过程中,若子树为空,则停止子树的访问进行后续的遍历。

同样是上面那张图,后续遍历的结果为:7 6 4 2 5 3 1 。

后序遍历的递归实现和上面两种是大致相同的,唯一的区别只是访问顺序不同,代码如下:

void preorder(node* root) {
	if(root==NULL)             //到达递归边界,回退 
		return;
	preorder(root->lchild);    //访问左子树 
	preorder(root->rchild);    //访问右子树 
	cout<<root->data<<endl;    //访问根节点 
}

9.2.4 层序遍历

可以看到,二叉树的先序、中序、后续的实现思路是相同的。其实这种思想我们在DFS中已经学习,一层一层的递归实际上就是栈的实现。而层序遍历则和BFS有着相同的思想,应用的数据结构为队列。

层序遍历是指按层次的顺序从根节点向下逐层进行遍历,且对同一层进行从左到右的顺序。层序遍历从逻辑上非常直观,例如下面这个例子,层序遍历的结果为:1 2 3 4 5 6 。

这个过程和BFS很像,因为BFS进行搜索总是以广度为第一关键词,对应到二叉树中广度就体现在层次上。因此层次遍历就是二叉树从根节点开始的广度优先搜索,其思路就是BFS的思路:

(1)将根节点入队;

(2)访问队首结点,然后队首出队;

(3)如果该结点有左孩子,则左孩子入队;

(4)如果该节点有右孩子,则右孩子入队;

(5)返回第二步循环,直到队列为空时退出循环。

代码如下:

void Layerorder(node* root) {
	queue<node*> q;
	q.push(root);
	while(!q.empty()) {
		node *now=q.front();     //访问该节点 
		q.pop();
		if(now->lchild) {
			q.push(now->lchild)
		}
		if(now->rchild) {
			q.push(now->rchild)
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值