int dist[n],state[n],pre[n];
dist[1] = 0;
for(i : 1 ~ n)
{
t <- 没有连通起来,但是距离连通部分最近的点;
state[t] = 1;
更新 dist 和 pre;
}



#include
#define MaxVertexNum 100
typedef char VertexType;
typedef int EdgeType;
int Max = 0x3f3f3f3f;
typedef struct {
VertexType Vex[MaxVertexNum];
EdgeType EdgeType[MaxVertexNum][MaxVertexNum];
int vexnum, arcnum;
} Gragh;
//BFS遍历
bool visited[MaxVertexNum];
void BFSTraverse(Graph G) {
for (int i = 0; i < G.vexnum; ++i)
visited[i] = false;
InitQueue(Q);
for (int i = 0; i < G.vexnum; ++i)
if (!visited[i])
BFS(G, i);
}
void BFS(Graph G, int v) {
visit(v);
visited[v] = true;
Enqueue(Q, v);
while (!isEmpty(Q)) {
DeQueue(Q, v);
for (w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w))
if (!visited[w]) {
visit(w);
visited[w] = true;
EnQueue(Q, w);
}
}
}
//BFS求单源最短路径
void BFS_MIN_Distance(Graph G, int u) {
//d[i]表示从u到i结点的最短路径
for (int i = 0; i < G.vexnum; i++){
d[i] = Max; //初始化路径为无穷
path[i]=-1;//最短路径从哪个顶点过来
}
visited[u] = true;
d[u] = 0;
EnQueue(Q, u);
while (!isEmpty(Q)) {
DeQueue(Q, u);//队头元素u出队
for (w = FirstNeighbor(G, u); w >= 0; w = NextNeighbor(G, u, w))//找到和它相邻的所有结点+
if (!visited[w]) {//w为u的尚未访问的邻接顶点
visited[w] = true;//设已访问的标记
d[w] = d[u] + 1;//路径长度+1
path[w]=u;//最短路径应该是从u到v
EnQueue(Q, w);//顶点w入队
}//if
}//while
}
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
|---|---|---|---|---|---|---|---|---|
| d[] | ∞ | ∞ | ∞ | ∞ | ∞ | ∞ | ∞ | ∞ |
| path[] | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
| visited[] | false | false | false | false | false | false | false | false |
② 修改起始节点的数组,并且将2结点压入队列中
队列:2
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
|---|---|---|---|---|---|---|---|---|
| d[] | ∞ | 0 | ∞ | ∞ | ∞ | ∞ | ∞ | ∞ |
| path[] | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
| visited[] | false | true | false | false | false | false | false | false |
③ 非空进入while循环,取出队首元素2,判断与2相连的所有结点:1,6,1结点的visited为false,1的d[]数组改为1+d[2],并且path[1]=2,表示与结点2距离为1,并且最短路径中前驱是2,并且将1压入队列;6号结点同理,6的d[]数组改为1+d[2]=1,并且path[6]=2,visited[6]=true,并且将6压入队列
队列:1、6
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
|---|---|---|---|---|---|---|---|---|
| d[] | ∞ | 0 | ∞ | ∞ | ∞ | ∞ | ∞ | ∞ |
| path[] | -1 | -1 | -1 | -1 | -1 | 1 | -1 | -1 |
| visited[] | false | true | false | false | false | true | false | false |
④ 取出队首1,判断1的连通未访问的顶点为5,则5的d[5]改为d[1]+1=1+1=2,path[5]=1,visited[5]=1,入队
队列:6、5
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
|---|---|---|---|---|---|---|---|---|
| d[] | ∞ | 0 | ∞ | ∞ | 2 | ∞ | ∞ | ∞ |
| path[] | -1 | -1 | -1 | -1 | 1 | 1 | -1 | -1 |
| visited[] | false | true | false | false | true | true | false | false |
⑤ 判断6 判断5即可得到
队列:1、6
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
|---|---|---|---|---|---|---|---|---|
| d[] | 1 | 0 | 2 | 3 | 2 | 1 | 2 | 3 |
| path[] | 2 | -1 | 6 | 3 | 1 | 2 | 6 | 7 |
| visited[] | true | true | true | true | true | true | true | true |
得到上述表格,问2到8的路径=d[8]=3,路径逆向思维进行寻找,8前为7,7前为6,6前为2,得到:2->6->7->8
4. 分析:广度优先生成树其实层数就反映了到达其他节点的最短路径,换句话说,利用广度优先构造的最小生成树,高度一定是最小的。
| v0 | v1 | v2 | v3 | v4 | |
|---|---|---|---|---|---|
| final[] | √ | × | × | × | × |
| dist[] | 0 | 10 | ∞ | ∞ | 5 |
| path[] | -1 | 0 | -1 | -1 | 0 |
如图所示:当前可以确定的是v0可以到v4,可以到v1,分别是5,10,写入数组,并且修改path1,4的前驱为0 。
② 第一轮,循环遍历所有结点,找到目前还没有确定最短路径,且dist最小的顶点v,令final[i]=ture。如本题,最小dist为4的5,即可以说明v0到v4的最短路径为5,修改final[4]=√,并且检查所有和v4相邻的顶点,寻找有没有可能v0经过v4到其他点路径更近,发现v0v4v1长度为5+3=8<10=v0v1,所以让dist[1]=8,同理dist[2]=5+9=14,path[2]=4,dist[3]=7,path[3]=4。
| v0 | v1 | v2 | v3 | v4 | |
|---|---|---|---|---|---|
| final[] | √ | × | × | × | √ |
| dist[] | 0 | 8 | 14 | 7 | 5 |
| path[] | -1 | 4 | 4 | 4 | 0 |
③第二轮,随后检查所有final值为false的顶点的,发现目前dist最小的是7,则处理3顶点,让final为√,表示已经可以确定v0->v3最短为7,且路径为0->4->3,然后检查所有v0经过v3到达的顶点vi,修改得
| v0 | v1 | v2 | v3 | v4 | |
|---|---|---|---|---|---|
| final[] | √ | × | × | √ | √ |
| dist[] | 0 | 8 | 13 | 7 | 5 |
| path[] | -1 | 4 | 3 | 4 | 0 |
④ 检查所有final值为×的结点,选择1,更新后检查v4,v2,因为v4之前已经确定了,所以无需检查只要看v2即可,
⑤ 一直到final值全部为√。
| v0 | v1 | v2 | v3 | v4 | |
|---|---|---|---|---|---|
| final[] | √ | √ | √ | √ | √ |
| dist[] | 0 | 8 | 9 | 7 | 5 |
| path[] | -1 | 4 | 1 | 4 | 0 |
final[0]=ture;dist[0]=0;path[0]=-1;
final[k]=false;dist[k]=arcs[0][k];path[k]=(arcs[0][k]==∞)?-1:0;
(2)需要经过n-1轮循环,循环遍历所有结点,找到还没有确定最短路径,且dist最小的顶点vi,令final[i]=true。检查所有邻接自vi的顶点,对于邻接自vi的顶点vj,若final[j]==false且dist[i]+arcs[i][j]
(4)和prim算法很是相似,时间复杂度也是相似的
(5)注意:如果带权图中权值有负数,则这个算法将会出错,不适用。

② 以 A 为「中转站」,刷新所有「入度」和「出度」的距离,A 的入度有 B 、D 2点,A 的出度也是 B、D 2,BA + AD > BD,DA + AB > DB,所以没有更小的距离,不能「刷新距离」,A[][] 和 path[][] 不刷新。
③ 以 B 为「中转站」,刷新所有的「入度」和「出度」的距离,B 的入度有 A、C、D;B 的出度有 A、C、D。(所以一共有 6 种组合):
(1) AB + BC < AC ( 2 + 3 < 无穷大,这里的 -1 代表无穷大),将 AB + BC 的距离 5 赋值给 AC 距离 -1,即 A[0][2] = A[0][1] +A[1][2],AC 的最短距离不再是直线 AC 的最短距离,引入「中转站」B 点,即 path[0][2] = 1
(2)AB + BD < AD ( 2 + 2 < 6),将 AB + BD = 4 的值赋值给 AD,即 A[0][3] = A[0][1] +A[1][3],AD的最短距离不再是直线 AD 的最短距离,引入「中转站」B 点,即 path[0][3] = 1。
(3) DB + BC < DC(2 + 3 < 2 ,不用刷新距离)

④ 最后结果:
A
0 2 5 4
2 0 3 2
5 3 0 2
4 2 2 0
path
0 1 1 1
0 1 2 3
1 1 2 3
1 1 2 3
typedef struct struct_graph{
char vexs[MAXN];
int vexnum;//顶点数
int edgnum;//边数
int matirx[MAXN][MAXN];//邻接矩阵
} Graph;
(2)Floyd
//这里是弗洛伊德算法的核心部分
//k为中间点
for(k = 0; k < G.vexnum; k++){
//v为起点
for(v = 0 ; v < G.vexnum; v++){
//w为终点
for(w =0; w < G.vexnum; w++){
if(D[v][w] > (D[v][k] + D[k][w])){
D[v][w] = D[v][k] + D[k][w];//更新最小路径
P[v][w] = P[v][k];//更新最小路径中间顶点
}
}
}
}
(3)求最短距离
v = 0;
w = 3;
//求 0 到 3的最小路径
printf("\n%d -> %d 的最小路径为:%d\n", v, w, D[v][w]);
k = P[v][w];
printf("path: %d", v);//打印起点
while(k != w){
printf("-> %d", k);//打印中间点
k = P[k][w];
}
printf("-> %d\n", w);
| BFS算法 | Dijkstra算法 | Floyed算法 | |
|---|---|---|---|
| 无权图 | √ | √ | √ |
| 带权图 | × | √ | √ |
| 带负权值的图 | × | × | √ |
| 带负权回路的图 | × | × | × |
| 时间复杂度 | O(V2)/O(V+E) | O(V2) | O(V3) |
| 通常用于 | 带无权图的单源最短路径 | 求带权图的单源最短路径 | 求带权图中各个顶点间的最短路径 |
注意:也可以使用Dijkstra算法求取各个顶点之间的最短路径,重复V次即可,时间复杂度也是O(V3)。

①从AOV网中选择一个没有前驱(入度为0)的顶点并输出。
② 从网中删除该顶点的所有以它为起点的有向边。
③ 重复①和②直到当前的AOV网为空或当前网中不存在无前驱的顶点为止。
4. 每个AOV网会有多个拓扑排序,不是所有的图都会有拓扑排序,有回路的图是不存在拓扑排序的

Status TopologicalSort(ALGraph G, int topo[]) {
//有向图G采用邻接表存储结构
//若G无回路,则生成G的一个拓扑排序topo[]并返回OK,否则ERROR
FindInDegree(G, indegree);//求出各结点的入度存入数组indegree中
SqStack S;
InitStack(S);//初始化栈
for (int i = 0; i < G.vexnum; i++) {
if (!indegree[i]) Push(S, i);//入度为0者进栈
}
int m = 0;//对输出顶点计数u,初始为0
while (!StackEmpty(S)) {
int i = 0;
Pop(S, i);//将栈顶顶点vi出栈
topo[m] = i;//将vi保存在拓扑序列数组topo中
++m;//对输出顶点计数
ArcNode* p = new ArcNode;
p = G.vertices[i].firstarc;//p指向vi的第一个邻接点
while (p != NULL) {
int k = p->adjvex;//vk为vi的邻接点
--indegree[k];//vi的每个邻接点的入度减一
if (indegree[k] == 0) Push(S, k);//若入度减为0,则入栈
p = p->nextarc;//p指向顶点vi下一个邻接结点
}
}
if (m < G.vexnum) return ERROR;//该有向图有回路
else return OK;
}
int visited[MAX];//设置一个数组,判断是否遍历过,false/1为遍历过
void DFGTraverse(Graph G,int v)
{
for(v=0;v<G.vexnum;v++)
visited[v]=0;//初始化判断数组
for(v=0;v<G.vexnum;v++)
{
if(!visited[v])//如果没有遍历过
DFS(G,V);//进行遍历
}
}
void DFS(Graph G,int v)//进行递归遍历
{
visited[v]=1;printf(v);//改变判断数组,输出点
for(w=FirstVex(G,v);w!=0;w=NextVex(G,v))//从每一行第一个邻接矩阵值为1的,跳转到下一个值为1的
{
if(!visited[w])
DFS(G,v);
}
printf(v);//不一样的地方
}


