二叉树的递归遍历

我们今天就讲一个简单的,递归遍历,但是一定要理解为什么是这样运行的,脑子要抽象一点。

食用此文章之前请先对树,二叉树有点了解

 递归遍历分为先序遍历,后序遍历,中序遍历,只要理解了一个那么就都理解了

1、如图这是一个先序遍历,先访问根节点,后访问左节点,然后右节点。

2、这个遍历函数非常简单,一个无返回值的函数,它的参数为二叉树首结点地址,if BT表示BT不为空的时候方可执行块中代码

3、我们以右边这张图为例,先序遍历到底如何得出的A B D F E C G H I这个结果。假设我们传递的是&A也就是首结点

//二叉树结点
typedef struct BINARYNODE {
	char ch;
	struct BINARYNODE* lchild;
	struct BINARYNODE* rchild;
}BinaryNode;

不用在意名字不一样,只是告诉各位这个二叉树的结点的结构是这样的。

头结点其实就是存放数据的,左右都是结点创建的指针。

进入正题

先序遍历

首先A结点不为空进入if,先访问根结点也就是打印A,A便打印完了

先访问左子树,所以函数的参数传递为左结点,抽象一点理解,因为左节点B也不为空所以打印B,因为对于调用的函数来说传入的B就是根结点

这是第一次调用函数,那么在打印完了B后,函数继续

调用函数,传递的参数为B的左节点也就是D。对于被调用的函数来说传入的结点就是根结点,那么访问D打印它,D打印完了

然后D函数调用函数,传递自身左节点作为参数

D的左结点为空,到此,D的左节点退出函数,结束。

回到D函数,D调用完了访问左结点的函数执行完成退出,可以开始调用访问右边的函数,传递D的右结点作为函数参数,因为D的右结点也是空,那么退出函数,此时D也运行完了,可以回到调用D的B。

B的第一个函数,也是就访问左结点的函数结束了,可以开始执行第二个函数,也就是传递自身的右结点作为函数参数。也就是进入到了F,F不为空,满足要求,打印F。

F调用函数以自身的左结点作为参数,也就是E,E不为空,打印E,E调用自身的左节点,右节点作为函数参数,都是空,所以退出,执行完了E

E执行完成,回到F,F的的第一个函数执行完,调用第二个函数,以自身的右结点作为参数调用,F右结点为空,不满足要求,直接退出函数。

到此F执行完,回到B,B就是用第二个函数,右边结点做参数调用的F,所以B也执行完,回到A,此时A的左边所有结点都打印访问完毕

其实也就是相当于A的第一个函数结束了,即以左结点为参数的函数结束了,右结点要开始调用。

A以自身右结点为参数调用函数,即C,打印C,C先以自身左结点为参数调用函数,即G,不为空,那么打印G。

打印完G,G以自身左节点调用函数,为空,直接退出,回到G,G以右结点为参数调用函数,不为空,打印H,H左右都为空,最后退出结束H,回到G,到此G结束,G回到C

到此C的左节点访问完毕,C访问右结点,I打印,I已经没有结点,都为空,那么退出I,C结束,那么A结束,那么递归结束。

A B D F E C G H I

很多地方用词不太准确,只需要理解到底如何递归访问的即可,毕竟函数也就四句话

 我说的全部流程都是第一张图右边那个表,大家对照理解即可。

中序和后序无非是交换顺序而已,就不拿这老图了,给大家看看我写的

//二叉树结点
typedef struct BINARYNODE {
	char ch;
	struct BINARYNODE* lchild;
	struct BINARYNODE* rchild;
}BinaryNode;

//递归遍历
void Recursion(BinaryNode*root) {
	if (root == NULL) {
		return;
	}

	//先序遍历
	//先访问根节点
	printf("%c", root->ch);
	//再遍历左子树
	Recursion(root->lchild);
	//再遍历右字数
	Recursion(root->rchild);

	中序遍历
	先遍历左子树
	//Recursion(root->lchild);
	再访问根节点
	//printf("%c", root->ch);
	再遍历右字数
	//Recursion(root->rchild);

	//Recursion(root->lchild);//左
	//Recursion(root->rchild);//右
	//printf("%c", root->ch);//根
}

和上面讲的其实没什么区别,不过我的树不是PPT上这个结构,感觉PPT上的这个二叉树很好讲。

中序遍历

中序遍历的依旧是一张图解

 如图依旧是递归,我们就不再讲那么啰嗦了,首先中序遍历是左 中 右的访问

我们直接带入计算,首先A进入函数,A不为空执行调用函数,A传递左边结点

进入B,B不为空,B指向左边的D

进入D,D的左为空,当结束左后回到D执行第二句话,打印D

第三句D传递右边的参数,D为空,结束。

D结束,则B的左结点函数调用结束,打印B

第三句传递B的右结点为参数,进入F

F不为空,F进入左结点,E不为空,E左为空,打印E

右为空,E结束,回到F,打印F

F右结点为空,F结束,回到B,B结束,回到A 打印A

至此左边结点全部遍历完,同时退出打印完A,开始遍历右边

A右节点,进入C,C左节进入G,G左结点为空,打印G

G右结点为H,进入H,H左为空,打印H

右为空,H结束,回到G,G结束

G结束回到C,打印C

C右为I,进入I,I左为空,打印I

I右也为空,I结束,回到C,C结束,回到A,A结束

 

 后序遍历,这个大家如果前面的理解了相信看一眼就会了

我们详细介绍了递归的调用和栈解退的步骤,还需要自己理解

最后强调一点,根结点就相当于自身的数据域一样,学过链表的应该会有感觉

大多数的数据结构和众多算法会用到递归,没办法,的确好用,除了不是很适合理解,也只能这么讲了,一定要能抽象的自己去想

还看不懂也可以去看看课,还是不错的

【浙江大学】数据结构_哔哩哔哩_bilibili

  • 12
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值