时间复杂度 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;
}
};
(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
#include
#include
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
#include
#include
#include
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;
}