2021-08-06


浙江大学慕课数据结构第三章树

二叉树

有左右之分的度为2的树,有三种结点(孩子数0,1,2),树的边N=结点树M-1。因此n0+n1+n2 -1= n1+2*n2,这样叶子的数就等于孩子数为2结点数+1。
二叉树遍历方法

用数组表示二叉树

可以先将二叉树按层次顺序编号,结点i左孩子序号为2i,但是对缺的结点会造成空间浪费.
在这里插入图片描述

用链表表示

是较好的方式

left_childdataright_child

在遍历二叉树的过程可以看作从父节点进入树递归的过程,每个父结点都有三次遍历到的机会,而先,中,后序可以看作第几次输出的过程(1,2,3)。
视频中讲述的中序遍历的非递归方法实际上也是递归的一种思想,递归本就可以看作是把上层函数存在堆栈中,等下层调用完成后再重新出栈。后序实际上是深度遍历,而层序遍历实际是广度遍历。

在遍历表达式树的时候通过先,中,后序方法可以得到先,中,后缀表达式(中缀需要加括号)。

课后练习:03-树3 Tree Traversals Again

在这里插入图片描述

在这里插入图片描述

题目给出了一个中序遍历二叉树所用栈的出栈入栈过程,需要输出树的后序遍历顺序,而这个出栈入栈的过程实际上暗藏了先序遍历的顺序(入栈的顺序),因为之前说过每个父结点都有三次遍历到的机会,而先,中,后序可以看作第几次遍历(1,2,3)的时候输出。所以按照递归的思想可以通过先序和中序求后序:
标准答案C++代码如下

#include<cstdio>
#include<stack>
#include<string>
#include<iostream>
using namespace std;
const int maxn=100;
int pre[maxn], in[maxn], post[maxn];
 
void solve(int PreL, int inL, int postL, int n){
	if(n==0)return;
	if(n==1){
		post[postL]=pre[PreL];
		return;
	}
	int i;
	int root=pre[PreL];
	post[postL+n-1]=root;
	for(i=0; i<n; i++){
		if(in[inL+i]==root)break;
	}
	int L=i, R=n-i-1;
	solve(PreL+1, inL, postL, L);//1,0,0,3
	solve(PreL+1+L, inL+L+1, postL+L, R);//4,4,3,2
}
int main(){
	int n, num, i=0, j=0;
	scanf("%d", &n);
	string s;
	stack<int> st;
	for(int z=0; z<2*n; z++){
		cin>>s;
		if(s=="Push"){
			scanf("%d\n", &num);
			st.push(num);
			pre[i++]=num;//1 234 56
		}else{
			num=st.top();
			st.pop();
			in[j++]=num;//324 1 65
		}
	}
	solve(0,0,0,n);//root pos in pre, tree pos in mid,first pos of tree,num of tree node
	for(int i=0; i<n; i++){
		printf("%d", post[i]);
		if(i!=n-1)printf(" ");
	}
	return 0;
}

首先通过两个数组收集了先序和中序的结点顺序,而后序的求法只需要按左子树->右子树->父结点顺序递归完成即可。过程就是先确定子树在后置数组中结点的存放范围【a,b】,a是左子树的左节点存放位置,b是root存放的位置,这里可以看见solve函数有四个参数,其中n就是子树所包含结点的个数,PreL是在前序数组中子树root的位置, inL是是子树的root在中序数组中的位置, postL就是上面的a,而b就是a+n-1。这样递归就相当于为每个结点分配好了数组中的位置,最后将后序数组打印出来即可。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值