树与图的遍历----深度优先遍历 and 层次优先遍历

1.DFS模板与BFS模板

时间复杂度 O(n+m), n 表示点数,m表示边数

(1) 深度优先遍历

int dfs(int u)
{
    st[u] = true; // st[u] 表示点u已经被遍历过

    for (int i = h[u]; i != -1; i = ne[i])
    {
        int j = e[i];
        if (!st[j]) dfs(j);
    }
}

(2) 宽度优先遍历
a.使用顺序存储结构

queue<int> q;
st[1] = true; // 表示1号点已经被遍历过
q.push(1);

while (q.size())
{
    int t = q.front();
    q.pop();

    for (int i = h[t]; i != -1; i = ne[i])
    {
        int j = e[i];
        if (!st[j])
        {
            st[j] = true; // 表示点j已经被遍历过
            q.push(j);
        }
    }
}

b.使用链式存储结构

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    vector<int> PrintFromTopToBottom(TreeNode* root) {
        //层次遍历
        vector<int> res;
        if(root==NULL)
            return res;
        queue<TreeNode*> q;
        q.push(root);
        while(!q.empty()){
            res.push_back(q.front()->val);
            if(q.front()->left!=NULL)
                q.push(q.front()->left);
            if(q.front()->right!=NULL)
                q.push(q.front()->right);
            q.pop();
        }
        return res;
    }
};

c.按层进行输出

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        //层次遍历
        vector<vector<int>> res;
        vector<int> tmp;
        queue<TreeNode*> q;

        if(root)
            q.push(root);
        int levelCount=1,count=0;

        while(!q.empty()){
            TreeNode *now=q.front();
            q.pop();
            tmp.push_back(now->val);
            --levelCount;

            if(now->left){
                q.push(now->left);
                ++count;
            }
            if(now->right){
                q.push(now->right);
                ++count;
            }

            if(levelCount==0){
                levelCount=count;
                count=0;

                res.push_back(tmp);
                tmp.clear();
            }
        }

        return res;
    }
};

2.示例

(1) 深度优先遍历

给定一颗树,树中包含n个结点(编号1~n)和n-1条无向边。

请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。

重心定义:重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。

输入格式

第一行包含整数n,表示树的结点数。
接下来n-1行,每行包含两个整数a和b,表示点a和点b之间存在一条边。

输出格式

输出一个整数m,表示重心的所有的子树中最大的子树的结点数目。
数据范围1≤n≤105

输入样例

9
1 2
1 7
1 4
2 8
2 5
4 3
3 9
4 6

输出样例:

4

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 100010;

//邻接表存储树
int h[N], e[2*N], ne[2*N], idx;		//对于每个点k,开一个单链表,存储k所有可以走到的点。h[k]存储这个单链表的头结点
bool st[N];
int n, ans = N;

//添加一条边:插入一条a指向b的边,就是在a所在的邻接表里插入一个结点b
void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx, ++idx;
}

int dfs(int u)
{
	st[u] = true; // st[u] 表示点u已经被遍历过

	int size = 0, sum = 0;	//size 为连通图大小 sum为包含点数(以当前点为根节点的个数)
	for (int i = h[u]; i != -1; i = ne[i])
	{
		int j = e[i];
		if (!st[j]) {
			int s = dfs(j);        //子树大小
			size = max(size, s);
			sum += s;
		}
	}

	size = max(size, n - sum - 1);
	ans = min(size, ans);

	return sum + 1;
}

int main()
{
	memset(h, -1, sizeof h);

	//input
	int a, b;
	cin >> n;

	//process
	for (int i = 0; i < n-1; i++)
	{
		cin >> a >> b;
		add(a, b), add(b, a);
	}
	dfs(1);

	//output
	cout << ans << endl;

	return 0;
}

(2) 宽度优先遍历
给定一个n个点m条边的有向图,图中可能存在重边和自环。

所有边的长度都是1,点的编号为1~n。

请你求出1号点到n号点的最短距离,如果从1号点无法走到n号点,输出-1。

输入格式

第一行包含两个整数n和m。
接下来m行,每行包含两个整数a和b,表示存在一条从a走到b的长度为1的边。

输出格式

输出一个整数,表示1号点到n号点的最短距离。
数据范围1≤n,m≤105

输入样例:

4 5
1 2
2 3
3 4
1 3
1 4

输出样例:

1

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

const int N = 100010;

//邻接表存储树
int h[N], e[N], ne[N], idx;		//对于每个点k,开一个单链表,存储k所有可以走到的点。h[k]存储这个单链表的头结点
bool st[N];
int n, m;
int d[N];	//每个节点到起点的距离


//添加一条边:插入一条a指向b的边,就是在a所在的邻接表里插入一个结点b
void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx, ++idx;
}

int bfs()
{
	queue<int> q;
	st[1] = true;
	q.push(1);

	memset(d, -1, sizeof d);
	d[1] = 0;

	while (q.size()) {
		int t = q.front();
		q.pop();

		for (int i = h[t]; i != -1; i = ne[i]) {
			int j = e[i];

			if(d[j]==-1) {      //如果j没有被扩展过
				d[j] = d[t] + 1;	

				st[j] = true;
				q.push(j);
			}
		}
	}

	return d[n];
}

int main()
{
	memset(h, -1, sizeof h);

	//input
	int a, b;
	cin >> n >> m;

	//process
	for (int i = 0; i < m; i++)
	{
		cin >> a >> b;
		add(a, b);
	}

	//output
	cout << bfs() << endl;

	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43202635/article/details/107491345