图总结
一.思维导图
二.重要概念笔记
1.图的存储结构
-有向图:i行非0元素的个数(邻接矩阵存储)或第i个链表边节点的个数(邻接表存储) 等于该节点的出度OD,所有行非0元素个数和或所有链表边节点个数和等于边数e。
-无向图:第i行非0元素的个数(邻接矩阵存储)或第i个链表边节点的个数(邻接表存储) 等于该节点的度TD,所有行非0元素个数和或所有链表边节点个数和等于两倍边数2e。
-邻接矩阵:
(1)要判断任意两顶点是否有边无边就很容易了;
(2)要知道某个顶点的度,其实就是这个顶点vi在邻接矩阵中第i行或(第i列)的元素之和;
(3)求顶点vi的所有邻接点就是将矩阵中第i行元素扫描一遍,arc[i][j]为1就是邻接点;
-邻接表:
(1)图中顶点用一个一维数组存储,当然,顶点也可以用单链表来存储,不过,数组可以较容易的读取顶点的信息,更加方便。
(2)图中每个顶点vi的所有邻接点构成一个线性表,由于邻接点的个数不定,所以,用单链表存储,无向图称为顶点vi的边表,有向图则称为顶点vi作为弧尾的出边表。
2.拓补排序
-算法:
(1)找到一个没有后继的顶点;
(2)把它放入数组中,并且从图中删除顶点以及连接到它的边;
(3)不断进行(1)和(2),如果找不到没有后继的顶点了,但是数组中的顶点数量还没达到图的顶点数量,说明图中必然存在环。
3.图的遍历
-
-单次DFS或BFS的时间复杂度为O(连通/强连通分量的边数)。
-DFS/BFS:单次调用可得到一个连通分量/强连通分量(访问的点+关联的所有边),
-DFS:亦可得到该分量的一棵生成树(点连成的边);可再单次调用DFS时看是否遇到访问过的节点来判断是否有环。
4.最短路径
-Dijkstra算法求单源最短路径:
(1)从T中选择一个未标记的权值最小的顶点w,将w加入S,并对w进行标记。若所有点都被标记,则结束。
(2)考察T中的所有顶点,对路径进行松弛
(注意:无向图和有向图都适用,弧的权值必须非负。)
-Floyd算法求每对顶点间最短路径:
(1)初始设置一个n阶方阵,令其对角线元素为0,若存在弧<vi,vj>,则对应元素为权值,否则为无穷。
(2)逐步试着在原直接路径中增加中间顶点,若加入中间点后路径变短,则修改。否则,维持原值。
(3)所有顶点试探完毕,算法结束。
5.AOE网和AOV网
-AOV、AOE网络都是有向图。
(1)、AOV网络用节点表示活动,一些活动间有先后关系,所以组成了有向图。
判断活动能否顺利开展(即图是否有环):拓扑排序、深度优先遍历,时间复杂度均为O(n+e)
(2)、AOE网络:顶点表示事件、边表示活动。
某顶点表示的事件发生后从该顶点出发的各有向边表示的活动才能发生;进入某顶点的各有向边表示的活动发生后该顶点表示的事件才能发生。
三.疑难问题解决
-
#include <iostream>
#include <queue>
using namespace std;
typedef struct ANode
{
int adjvex; //该边的终点编号
struct ANode* nextarc; //指向下一条边的指针
int info; //该边的相关信息,如权重
} ArcNode; //边表节点类型
typedef int Vertex;
typedef struct Vnode
{
Vertex data; //顶点信息
ArcNode* firstarc; //指向第一条边
} VNode; //邻接表头节点类型
typedef VNode AdjList[MAXV];
typedef struct
{
AdjList adjlist; //邻接表
int n, e; //图中顶点数n和边数e
} AdjGraph;
int visited[MAXV];
int n;
void CreateAdj(AdjGraph*& G, int n, int e); //创建图邻接表
void BFS(AdjGraph* G, int v); //v节点开始广度遍历
int main()
{
cout.setf(ios::fixed);
cout.precision(2);
AdjGraph* G;
int e, i, v,j;
cin >> n >> e;
CreateAdj(G, n, e);
for (i = 1; i <= n; i++) {
BFS(G, i);
for (j = 1; j <= n; j++)visited[j] = 0;
}
}
void CreateAdj(AdjGraph*& G, int n, int e) {
G = new AdjGraph;
ArcNode* p, * q;
int i, j, k;
int a, b;
for (i = 0; i <= n; i++) {
G->adjlist[i].firstarc = NULL;
G->adjlist[i].data = i;
visited[i] = 0;
}
for (i = 0; i < e; i++) {
cin >> a >> b;
p = new ArcNode;
q = new ArcNode;
p->adjvex = b;
q->adjvex = a;
p->nextarc = G->adjlist[a].firstarc;
q->nextarc = G->adjlist[b].firstarc;
G->adjlist[a].firstarc = p;
G->adjlist[b].firstarc = q;
}
G->n = n;
G->e = e;
}
void BFS(AdjGraph* G, int v) {
int i=-1,b;
int a;
double sum = 0;
ArcNode* p;
queue<int>q;
q.push(v);
b = q.back();
visited[v] = 1;
while (!q.empty()&&i<6) {
sum++;
a = q.front();
p = G->adjlist[a].firstarc;
while (p) {
if (!visited[p->adjvex]) {
q.push(p->adjvex);
visited[p->adjvex] = 1;
}
p = p->nextarc;
}
if (q.front() == b) {
b = q.back();
i++;
}
q.pop();
}
cout << v << ": " << sum / n * 100 << "%" << endl;
}