当前位置:   article > 正文

一般树的遍历(算法笔记)_一般树的后序遍历

一般树的后序遍历

本文内容基于《算法笔记》和官方配套练题网站“晴问算法”,是我作为小白的学习记录,如有错误还请体谅,可以留下您的宝贵意见,不胜感激。


一、树的静态写法

本节讨论的“树”是指一般意义上的树,即子结点个数不限且子结点没有先后次序的树,而不是上文中讨论的二叉树。
首先来回顾二叉树的结点的定义,可以注意到它是由数据域和指针域组成的,其中左指针域指向左子树根结点的地址,右指针域指向右子树根结点的地址。借鉴这种定义方法,对一棵一般意义的树来说,可以仍然保留其数据域的含义,而令指针域存放其所有子结点的地址(或者为其开一个数组,存放所有子结点的地址)。不过这听起来有点麻烦,所以还是建议在考试中使用其静态写法,也就是用数组下标来代替所谓的地址。但这样可能会导致内存使用超过题目限制,因此可以采用vector模板来存储结点。(摘自算法笔记)

二、树的先根、后跟和层次遍历

区别于二叉树,树没有左右子树一说,因此在DFS中,树只有先根和后根遍历,区别在于根和子节点的先后访问顺序,子节点代表岔道口,当不存在结点时即代表走到了死胡同。
树的层次遍历就是BFS,这个没有什么不同。通过例题来感受:
在这里插入图片描述
在保证除输出序列改变而题干不变的情况下,分别采用先根、后根和层次遍历实现,用静态写法实现代码如下,注意递归边界的体现
DFS:

#include<cstdio>  
#include<vector>
using namespace std;

const int MAXN = 51;
struct Node{
	vector <int> child;
}node[MAXN];
int count = 1 , n;

void preOrder(int root){    //先根 
	printf("%d", root);
	if(count <= n - 1) {
		printf(" ");	
		count++;
	}
	for(int i = 0; i < node[root].child.size(); i++)   //第二个表达式就是递归边界 
		preOrder(node[root].child[i]);
}

void postOrder(int root){  //后根 
	for(int i = 0; i < node[root].child.size(); i++)   //第二个表达式就是递归边界 
		preOrder(node[root].child[i]);
	printf("%d", root);
	if(count <= n - 1) {
		printf(" ");	
		count++;
	}
}

int main(){
	scanf("%d", &n);
	for(int i = 0; i <= n - 1; i++){
		int k;
		scanf("%d", &k);
		for(int j = 0; j <= k - 1; j++){
			int temp;
			scanf("%d", &temp);
			node[i].child.push_back(temp);
		}	
	}
	preOrder(0);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

BFS:

#include<cstdio>
#include<vector>
#include<queue>
using namespace std;

const int MAXN = 51;
struct Node{
	vector <int> child;
}node[MAXN];
int count = 1 , n;

void BFS(int root){
	queue <int> qe;
	qe.push(root);
	while(!qe.empty()){
		int top = qe.front();
		qe.pop();
		printf("%d", top);
		if(count <= n - 1) {
			printf(" ");
			count++;
		}
		for(int i = 0; i < node[top].child.size(); i++)
			qe.push(node[top].child[i]);
	}
}

int main(){
	scanf("%d", &n);
	for(int i = 0; i <= n - 1; i++){
		int k;
		scanf("%d", &k);
		for(int j = 0; j <= k - 1; j++){
			int temp;
			scanf("%d", &temp);
			node[i].child.push_back(temp);
		}	
	}
	BFS(0);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

三、其余小题练习

1.树的高度
在这里插入图片描述
树是带有递归性质的,所以求树的高度就是求最大递归深度,用计数器即可实现,完整代码如下:

#include<cstdio>  
#include<vector>
using namespace std;

const int MAXN = 51;
struct Node{
	vector <int> child;
}node[MAXN];
int count = 1 , n;
int maxans = -1;

void preOrder(int root , int index){
	if((int)node[root].child.size() == 0 && maxans < index) maxans = index;  //这就是递归边界,只是隐含在了下面的循环中,最好还是写上这句 
	for(int i = 0; i < node[root].child.size(); i++)   //第二个表达式就是递归边界 
		preOrder(node[root].child[i] , index + 1);
}

int main(){
	scanf("%d", &n);
	for(int i = 0; i <= n - 1; i++){
		int k;
		scanf("%d", &k);
		for(int j = 0; j <= k - 1; j++){
			int temp;
			scanf("%d", &temp);
			node[i].child.push_back(temp);
		}	
	}
	preOrder(0 , 1);
	printf("%d", maxans);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

2.树的结点层号
在这里插入图片描述
老问题了,可以采用BFS+计数器的方式实现,也可以采用DFS+计数器的方式实现,把计数器放到结构体里就好,每向下一层就动态更新层号,完整代码如下:

#include<cstdio>
#include<vector>
#include<queue>
using namespace std;

const int MAXN = 51;
struct Node{
	vector <int> child;
	int step;
}node[MAXN];
int count = 1 , n;

void BFS(int root){
	queue <int> qe;
	qe.push(root);
	node[root].step = 1;
	while(!qe.empty()){
		int top = qe.front();
		qe.pop();
		for(int i = 0; i < node[top].child.size(); i++){
			qe.push(node[top].child[i]);
			node[node[top].child[i]].step = node[top].step + 1;
		}
	}
}

int main(){
	scanf("%d", &n);
	for(int i = 0; i <= n - 1; i++){
		int k;
		scanf("%d", &k);
		for(int j = 0; j <= k - 1; j++){
			int temp;
			scanf("%d", &temp);
			node[i].child.push_back(temp);
		}	
	}
	BFS(0);
	for(int i = 0; i <= n - 1; i++){
		printf("%d", node[i].step);
		if(i < n - 1) printf(" ");
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

3.树的路径和
在这里插入图片描述
记录走过的路径权值和,求到达叶结点时本条路径上的权值和,将所有叶结点的权值和相加即可。采用计数器实现,每进入一个子结点就将原有路径上的权值和传入子节点。完整代码如下:

#include<cstdio>  
#include<vector>
using namespace std;

const int MAXN = 51;
struct Node{
	int data;
	vector <int> child;
}node[MAXN];
int n , ans = 0;

void preOrder(int root , int w){
	if((int)node[root].child.size() == 0) ans += w;
	for(int i = 0; i < node[root].child.size(); i++)   //第二个表达式就是递归边界 
		preOrder(node[root].child[i] , w + node[node[root].child[i]].data);
}

int main(){
	scanf("%d", &n);
	for(int i = 0; i <= n - 1; i++)
		scanf("%d", &node[i].data);
	for(int i = 0; i <= n - 1; i++){
		int k;
		scanf("%d", &k);
		for(int j = 0; j <= k - 1; j++){
			int temp;
			scanf("%d", &temp);
			node[i].child.push_back(temp);
		}	
	}
	preOrder(0 , node[0].data);
	printf("%d", ans);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/169444
推荐阅读
相关标签
  

闽ICP备14008679号