【图论】图的存储--链式前向星存图法以及深度优先遍历图

图的存储

介绍

无向图-就是一种特殊的有向图->

只用考虑有向图的存储即可

有向图

  • 邻接矩阵
  • 邻接表

邻接表

存储结构:

(为每一个点开了一个单链表,存储这个点可以到达哪个点)

  • 1:3->4->null
  • 2:1->4->null
  • 3:4->null
  • 4:null
插入一条新的边

比如要插一条边:2->3

  • 先找到 2 对应的单链表
  • 然后将 3 插入到单链表里面去(一般使用头插)

对应的结构变化为:

  • 1:3->4->null
  • 2:3->1->4->null
  • 3:4->null
  • 4:null
插入边 Coding Part
c 复制代码
#include <iostream>
#include <cstring>
#define p(e) print(e, sizeof(e)/sizeof(int))
using namespace std;

const int N = 100010, M = N * 2;
//N表示结点数量上限,M表示结点数值上限

int h[N], e[M], ne[M], idx;

//插入一个a->b
inline void add(int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
	/*
		* idx是没有使用的空结点索引
		* 先给这个位置赋值b					# e[idx] = b
		* 然后让这个结点指向头结点			# ne[idx] = h[a]
		* 然后再更新头结点 					# h[a] = idx++
		* 同时让idx移动到新的空结点索引中去 # idx++
	*/
}

inline void print(int arr[], int n) {
	for (int i = 0; i < n; i++) cout << arr[i] << ' ';
	cout << endl;
}

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

遍历图

深度优先方法遍历图
  • 需要使用一个bool数组存放是否遍历的状态
  • 然后进行深度优先遍历
c 复制代码
#include <iostream>
#include <cstring>

using namespace std;

const int N = 100010, M = N * 2;
//N表示结点数量上限,M表示结点数值上限

int h[N], e[M], ne[M], idx;
bool st[N];
//插入一个a->b
inline void add(int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
	/*
		* idx是没有使用的空结点索引
		* 先给这个位置赋值b					# e[idx] = b
		* 然后让这个结点指向头结点			# ne[idx] = h[a]
		* 然后再更新头结点 					# h[a] = idx++
		* 同时让idx移动到新的空结点索引中去 # idx++
	*/
}

inline void dfs(int u) {
	st[u] = true;
	cout << u << ' ' ;
	for (int i = h[u]; i != -1; i=ne[i]) {
		int j = e[i];
		if (!st[j]) dfs(j);
	}
}

int main() {
	memset(h, -1, sizeof h);
	memset(st, false, sizeof st);
	add(1, 3);
	add(3, 5);
	add(3, 6);
	add(1, 2);
	add(1, 8);
	dfs(1);
}
题目:树的重心

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

请找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。
重心定义:重心是指树中的一个结点,如果将这个结点删除后,剩余各个连通块中点数的最大值最小,那么这个结点被称为树的重心。
输入格式

第一行包含整数 n,表示树的结点数。

接下来 n-1 行,每行包含两个整数 ab,表示 ab 之前存在的一条边。

输出格式

输出一个整数 m,表示重心的所有子树中最大子树的结点数目。

数据范围
1 <= n <= 105

输入样例

复制代码
9
1 2
1 7
1 4
2 8
2 5
4 3
3 9
4 6

输出样例

复制代码
4

答案代码

c 复制代码
#include <iostream>
#include <cstring>

using namespace std;

const int N = 100001, M = N*2;
int h[N], e[M], ne[M], idx;
bool st[N];

//a->b
void add(int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

/*遍历模板*/
void dfs_template(int u) {
	st[u] = true;
	cout << u << ' ';
	for (int i = h[u]; i != -1; i = ne[i]) {
		int j = e[i];
		if (!st[j]) {
			dfs_template(j);
		}
	}
}

int n;										//n为题目输入的结点数量
int ans = INT_MAX;							//初始化题目要求的最小值
int dfs(int u) {
	//每一棵树找到最大连通块的数量
	st[u] = true;
	int sum = 1, res = 0;							//sum统计子结点(包括自己)的数量, res统计儿子树最大连通块数量
	for (int i = h[u]; i != -1; i = ne[i]) {
		int j = e[i];
		if (!st[j]) {
			int s = dfs(j);
			sum += s;							//加上子节点的数量
			res = max(s, res);					//找到子树中的最大连通块
		}
	}
	res = max(res, n-sum);							//和父亲树进行比较
	ans = min(ans, res);							//更新答案
	return sum;
}

int main() {
	memset(h, -1, sizeof ne);
	cin >> n;
	for (int i = 0; i < n-1; i++) {
		int a, b;
		cin >> a >> b;
		add(a, b), add(b, a);
	}
	dfs(1);
	cout << ans << endl;
}
宽度优先方法遍历图

补充两个图论的概念:

  • 重边 : 例如,存在两条 1->2 的边,叫重边
  • 自环 :例如,1->1叫自环
题目:图中点的层次
相关推荐
旖-旎2 分钟前
深搜练习(组合总和)(7)
c++·算法·深度优先·力扣
小O的算法实验室12 分钟前
2026年ASOC,基于人工势场的差分进化算法改进框架,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
爱学习的张大17 分钟前
具身智能论文精读(五):OpenVLA
人工智能·算法
刘大猫.1 小时前
宝马发布全新AI智能座舱助手 能理解用户复杂出行需求
人工智能·算法·机器学习·ai·大模型·算力·ai智能座舱助手
如何原谅奋力过但无声1 小时前
【灵神高频面试题合集01-03】相向双指针、滑动窗口
数据结构·python·算法·leetcode
leoufung1 小时前
LeetCode 42:接雨水 —— 从“矩形法”到双指针的完整思考过程
java·算法·leetcode
_日拱一卒2 小时前
LeetCode:543二叉树的直径
算法·leetcode·职场和发展
汉克老师3 小时前
GESP2025年3月认证C++五级( 第一部分选择题(9-15))
c++·算法·高精度计算·二分算法·gesp5级·gesp五级
穿条秋裤到处跑3 小时前
每日一道leetcode(2026.04.28):获取单值网格的最小操作数
算法·leetcode·职场和发展
leoufung3 小时前
LeetCode 68. Text Justification 题解:贪心与实现细节
算法·leetcode·职场和发展