《算法笔记》读书记录DAY_33

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

9.3.1 树的静态写法

本节讨论一般意义的树,即子节点个数不限且子节点不分先后顺序。一般的树我们可以采取静态的写法。我们不采用链地址的方式来记录子节点位置,而采用数组下标的形式。结构体node定义如下:

struct Node {
	typedef data;      //数据域 
	vector<int> child;   //指针域,存放所有孩子结点的下标 
}node[maxn];

当需要新建一个结点时,就按顺序从数组中取出一个下标即可:

int index=0;

int newNode(int v) {
	node[index].data=v;         //数据域为v 
	node[index].child.clear();  //清空子节点 
	return index++;             //返回index,然后index自增 
}

有两点需要特别指出:

(1)在考试中涉及树(非二叉树)的考察时,一般给出结点编号,如:0、1、... 、n-1。这种情况下,就不需要newNode函数了。题目中给的结点编号可以直接用作数组下标,不需要我们创建index来统计结点了。

(2)如果题目中不涉及数据域,即只需要树的结构。那么结构体可以简化成vector数组,即vector<int> child[maxn]。这种写法其实就是下一章中图的邻接表的内容。

9.3.2 树的先根遍历

类似于二叉树的先序遍历,树的先根遍历也是同样的思路。我们总是先访问树的根节点,再去访问所有子树,这也同样是一个递归的过程,访问某一颗子树时,我们也是先访问它的根再访问它的子树。

代码如下:

void preOrder(int root) {
	cout<<node[root].data;
	for(int i=0;i<node[root].child.size();i++)
		preOrder(node[root].child[i]);
}

需要注意的是,代码中没有明显的体现递归边界,并不是不存在递归边界。而是递归边界隐含在循环中的判断条件i<node[root].child.size()里面,当前根节点没有孩子时,这个循环不会执行,即成为了递归边界。

9.3.3 树的层序遍历 

树的层序遍历与二叉树的层序遍历思路同样一致。 使用一个队列存放节点的数组中的下标(二叉树中是存放节点的地址),然后同样套用BFS的模板。代码如下:

void layerOrder(int root) {
	queue<int> q;             //存放节点下标的队列
	q.push(root);             //根节点下标入队
	while(!q.empty()) {
		int tmp=q.front();
		q.pop();              //队首出队
		cout<<node[tmp].data; //访问节点数据
		for(int i=0;i<node[tmp].child.size();i++) {
			q.push(node[tmp].child[i]);             //所有子节点入队 
		} 
	}
}

猜你喜欢

转载自blog.csdn.net/jgsecurity/article/details/120859972