本文已参与「新人创作礼」活动,一起开启掘金创作之路。
伪代码描述
时间复杂度
方法1: 解决稠密图
#include <iostream> //解决稠密图时
#include <algorithm>
using namespace std;
const int MaxV = 100;
const int INF = 10000; //表示无穷大,Weight < INF
/*定义边*/
typedef struct ENode{
int v1, v2;
int Weight;
} * Edge;
/*定义邻接矩阵图*/
typedef struct GNode{
int Nv, Ne;
int W[MaxV][MaxV];
string Data[MaxV];
} * MGraph;
/*初始化图*/
MGraph CreateGraph(int Nv)
{
MGraph G = new GNode;
G->Nv = Nv; G->Ne = 0;
for (int i = 0; i < G->Nv; i++)
for (int j = 0; j < G->Nv; j++)
G->W[i][j] = INF;
return G;
}
/*无向边的插入*/
void InsertEdge(MGraph G, Edge E)
{
G->W[E->v1][E->v2] = E->Weight;
G->W[E->v2][E->v1] = E->Weight;
}
/*输入图的数据,建立图*/
MGraph BuildGraph()
{
int Nv; cin >> Nv;
MGraph G = CreateGraph(Nv);
cin >> G->Ne;
Edge E = new ENode;
for (int i = 0; i < G->Ne; i++)
{
cin >> E->v1 >> E->v2 >> E->Weight;
InsertEdge(G, E);
}
delete E;
return G;
}
/*稠密图的找最小dist*/
int FindMinDist(MGraph G, int dist[], bool tag[])
{
int MinDist = INF;
int MinV;
for (int i = 0; i < G->Nv; i++)
if (!tag[i] && dist[i] < MinDist)
{
MinDist = dist[i];
MinV = i;
}
if(MinDist != INF)
return MinV;
else
return -1;
}
bool Dijkstra(MGraph G, int dist[], int path[], int s) //s为起点
{
/*初始化数组*/
bool tag[MaxV] = {0};
for (int i = 0; i < G->Nv; i++)
{
dist[i] = G->W[s][i];
if(dist[i] < INF)
path[i] = s;
else
path[i] = -1;
}
dist[s] = 0;
tag[s] = true;
while (1)
{
int v = FindMinDist(G, dist, tag);
if(v == -1)
break;
tag[v] = true;
for (int i = 0; i < G->Nv; i++)
if(!tag[i] && G->W[v][i] < INF) //如果没有访问过,且有边
{
if(G->W[v][i] < 0)
return false; //存在负边
if(dist[i] > dist[v] + G->W[v][i])
{
dist[i] = dist[v] + G->W[v][i];
path[i] = v;
}
}
}
return true;
}
/*输出最短路径*/
void Print(int path[], int v, int s) //给定终点输出最短路径
{
if (v < 0)
return;
Print(path, path[v], s);
if (v == s)
cout << v;
else
cout << "->" << v;
}
int main()
{
int dist[MaxV], path[MaxV];
MGraph G = BuildGraph();
if(!Dijkstra(G, dist, path, 0))
cout << "存在负边" << endl;
else
{
cout << "以0为起点到各点的最短路径为:" << endl;
for (int i = 1; i < G->Nv; i++)
{
Print(path, i, 0);
cout << " dist=" << dist[i] << endl;
}
}
delete G;
system("pause");
return 0;
}
input:
10 17
0 1 2
0 3 5
1 2 5
1 3 2
2 4 8
2 5 4
5 3 4
3 6 2
4 5 2
6 5 3
4 7 5
5 7 9
5 8 6
6 8 7
7 8 3
7 9 4
8 9 8
output:
以0为起点到各点的最短路径为:
0->1 dist=2
0->1->2 dist=7
0->1->3 dist=4
0->1->3->5->4 dist=10
0->1->3->5 dist=8
0->1->3->6 dist=6
0->1->3->5->4->7 dist=15
0->1->3->6->8 dist=13
0->1->3->5->4->7->9 dist=19
请按任意键继续. . .
方法2: 解决稀疏图
图的结构定义
#include <iostream> //解决稀疏图的Dijkstra算法
#include <algorithm>
using namespace std;
const int MaxV = 100;
const int INF = 100000;
/*************图的结构定义***************/
/*定义边*/
typedef struct ENode{
int v1, v2;
int Weight;
} * Edge;
/*定义邻接顶点*/
struct AdjVNode{
int AdjV;
int Weight;
AdjVNode *Next;
};
/*定义邻接表头*/
typedef struct VNode{
AdjVNode *EdgeFirst;
//string Data;
} AdjList[MaxV];
/*定义图*/
typedef struct GNode{
int Nv, Ne;
AdjList L;
} * LGraph;
图的操作
/*创造无边的图*/
LGraph CreateGraph(int Nv)
{
LGraph G = new GNode();
G->Nv = Nv;
return G;
}
/*给图插入有向边*/
void InsertEdge(LGraph G, Edge E)
{
AdjVNode *A = new AdjVNode;
A->AdjV = E->v2; A->Weight = E->Weight;
A->Next = G->L[E->v1].EdgeFirst;
G->L[E->v1].EdgeFirst = A;
}
/*建立一个有向网图*/
LGraph BuildGraph()
{
int Nv; cin >> Nv;
LGraph G = CreateGraph(Nv);
cin >> G->Ne;
Edge E = new ENode;
for (int i = 0; i < G->Ne; i++)
{
cin >> E->v1 >> E->v2 >> E->Weight;
InsertEdge(G, E);
}
delete E;
return G;
}
/*删除图*/
void DeleteGraph(LGraph G)
{
AdjVNode *A;
for (int i = 0; i < G->Nv; i++)
while (G->L[i].EdgeFirst)
{
A = G->L[i].EdgeFirst;
G->L[i].EdgeFirst = A->Next;
delete A;
}
delete G;
}
索引堆的结构定义
/***********最小索引堆结构定义************/
typedef struct HNode{
int *Index; //dist的索引
int *Reverse; //dist的索引的索引
int Size; //当前堆大小
int Capacity; //堆的容量
} * MinHeap;
堆的相关操作
/*************堆的操作**************/
/*最小索引堆的初始化*/
MinHeap CreateMinHeap(int MaxSize, int s) //存顶点的堆
{
MinHeap H = new HNode;
H->Size = 0; H->Capacity = MaxSize;
H->Index = new int[MaxSize + 1];
H->Reverse = new int[MaxSize + 1];
H->Index[0] = s; //哨兵,具体等于单源最短路径的起点S
return H;
}
/*由改过的Index[i] = j得到Rev[j] = i*/
void SwapIndex(MinHeap H, int i) //当Index有修改是修改Reverse
{
H->Reverse[H->Index[i]] = i;
}
/*最小堆元素改小,上滤, 与插入操作类似*/ //如果将i改为 ++H->Size就是插入操作
void Fix_up(MinHeap H, int i, int x, int dist[]) //将dist[i] 改为x,并调整最小堆, 相当于 dist[i] = x
{
dist[i] = x; //先修改
int child = H->Reverse[i];
for ( ; x < dist[H->Index[child / 2]]; child /= 2)
{
H->Index[child] = H->Index[child / 2]; //相当于 dist[child] = dist[child / 2]
SwapIndex(H, child);
}
H->Index[child] = i; //用dist作比较,Index做交换. 相当于 dist[child] = x
SwapIndex(H, child);
}
/*最小堆的插入, 上滤*/
void InsertIndex(MinHeap H, int v, int dist[]) //相当于 dist[i] = x (这与上面的不同, 这是在初始)
{
int child = ++H->Size; //dist[]元素个数与H->Index[]个数相同!!!! (在本算法中插入在开始前一次完成)
int x = dist[v];
for ( ; x < dist[H->Index[child / 2]] ; child /= 2) //上滤
{
H->Index[child] = H->Index[child / 2];
SwapIndex(H, child);
}
H->Index[child] = v; //此时插在dist[]的最后一个位置 , 最后得到dist[H->Size]的位置
SwapIndex(H, child);
}
/*返回堆最小元素的索引*/
int GetMinHeap(MinHeap H, int dist[]) //删除后dist[Index[1]] = 0
{
int v = H->Index[1];
int x = dist[H->Index[H->Size--]];
int child, parent;
for( parent = 1; parent * 2 <= H->Size; parent = child) //下滤
{
child = 2 * parent;
if(dist[H->Index[child + 1]] < dist[H->Index[child]] && child != H->Size)
child++;
if(x > dist[H->Index[child]])
{
H->Index[parent] = H->Index[child];
SwapIndex(H, parent);
}
else
break;
}
H->Index[parent] = H->Index[H->Size + 1];
SwapIndex(H, parent);
return v;
}
Dijkstra算法解决稀疏图
/****************Dijkstra算法*******************/
bool Dijkstra(LGraph G, int dist[], int path[], int s) //s为起点
{
/*初始化数组*/
bool tag[MaxV] = {0};
AdjVNode *A = G->L[s].EdgeFirst;
while (A) //遍历起点的所有边
{
dist[A->AdjV] = A->Weight;
path[A->AdjV] = s;
A = A->Next;
}
dist[s] = 0;
tag[s] = true;
/*建立索引最小堆存储dist[], 初始化堆*/
MinHeap H = CreateMinHeap(G->Nv, s);
for (int i = 0; i < G->Nv; i++)
if(i != s)
InsertIndex(H, i, dist);
while (H->Size > 0) //最小堆非空
{
int v = GetMinHeap(H, dist);
tag[v] = true; //表示已访问
A = G->L[v].EdgeFirst;
while (A)
{
if(!tag[A->AdjV]) //如果是没访问过的顶点
{
if(A->Weight < 0) //出现负边
return false;
if (dist[v] + A->Weight < dist[A->AdjV]) //如果是更短的路
{
Fix_up(H, A->AdjV, dist[v] + A->Weight, dist); //dist[A->AdjV] = dist[v] + A->Weight
path[A->AdjV] = v;
}
}
A = A->Next;
}
}
/*删除堆*/
delete[] H->Index;
delete[] H->Reverse;
delete H;
return true;
}
/*输出给定终点的最短路径*/
void Print(int path[], int v, int s)
{
if(v < 0)
return;
Print(path, path[v], s);
if(v == s)
cout << v;
else
cout << "->" << v;
}
main()函数
int main()
{
int dist[MaxV], path[MaxV];
int s; //起点
LGraph G = BuildGraph();
for (int i = 0; i < G->Nv; i++)
{
dist[i] = INF;
path[i] = -1;
}
cin >> s;
if(!Dijkstra(G, dist, path, s))
cout << "存在负边" << endl;
else
{
cout << "以" << s << "为起点到各点的最短路径为:" << endl;
for (int i = 1; i < G->Nv; i++)
{
Print(path, i, s);
cout << " dist=" << dist[i] << endl;
}
}
DeleteGraph(G);
system("pause");
return 0;
}
运行结果
input:
10 17
0 2 5
0 1 8
1 4 5
1 2 5
1 5 4
4 5 4
2 3 8
2 6 4
5 6 4
5 8 2
3 6 7
6 8 3
3 7 5
6 7 5
6 9 6
8 9 7
7 9 6
0
output:
以0为起点到各点的最短路径为:
0->1 dist=8
0->2 dist=5
0->2->3 dist=13
0->1->4 dist=13
0->1->5 dist=12
0->2->6 dist=9
0->2->6->7 dist=14
0->2->6->8 dist=12
0->2->6->9 dist=15
请按任意键继续. . .