包含:最小生成树(Prim算法,Kruskal算法),最短路径(Dijkstra算法,Floyd算法)
最小生成树
Prim算法
无符号整型的int最大的数值是65535 , 而普通的int占32位的时候,最大可以赋值为:21 4748 3647,约为20亿,2*10^9。
void Prim(MGraph G){
int adjvex[Maxvex]; // adjvex代表此时访问这个点是从那个点来的。0代表访问结点已经访问过了 //
int lowcost[Maxvex];// lowcost是访问当前结点的数值和距离。0代表已经加入生成树,无穷代表无关,有数据代表与当前 i 的距离
lowcost[0] = 0;//最初的时候
adjvex[0] = 0;
//初始化操作
for(int i = 1 ; i < G.vexnum ; i ++){ /
lowcost[i] = G.arc[0][i]; //这个代表的是从初始结点开始到各个结点的路径长
adjvex[i] = 0; // 保存邻接顶点下标
}
//Core
for(int i = 0 ; i < G.vexnum ; i ++){
int min = 65535; // 无符号整型的最大值为65535
int k = 0;
//找顶点
for(int j = 0 ; j < G.vexnum ; j ++){
if(lowcost[j] != 0 && lowcost[j] < min){ //尚未加入生成树,并且是当前最短的
min = lowcost[j]; // 距离当前 i 的最短的路径
k = j; // 最短路径到达的位置
}
}
printf("%d --> %d\n" , adjvex[k] , k);
lowcost[k] = 0; //标记为访问过
//更新表数据
for(int j = 0 ; j < G.vexnum ; j ++){
if(lowcost[j] != 0 && G.arc[k][j] < lowcost[j]){ //尚未加入生成树 , 并且可以更新为更短的
lowcost[j] = G.arc[k][j];
adjvex[j] = k; // 那些修改的点的下一坐标都改成从当前 k 开始
}
}
}
}
Kruskal算法
利用边
typedef struct{
int a , b;
int weight;
}Edge; //边结构体
//并查集:并
int Find(int *parent , int x){ //指针
while(parent[x] >= 0){
x = parent[x];
}
return x;
}
Edge edges[MaxVex];
int parent[MaxVex];
void Kruskal(MGraph G){
sort(edges);// 堆排序:权值递增排序
//并查集:初始化
for(int i = 0 ; i < G.vexnum ; i ++){
parent[i] = -1;
}
//搜索所有的边//
for(int i = 0 ; i < G.arcnum ; i ++){
n = Find(parent , edges[i].a);
m = Find(parent , edges[i].b);
if(n != m){ //当边的结点不在一个圈子内,合并起来
parent[n] = m; //并查集:并
printf("%d --> %d" , edges[i].a , edges[i].b);
}
}
}
最短路径
Dijkstra算法
#define INF 65535
/*
* v代表当前访问开始的结点
* path[]当前结点的来源
*/
void Dijkstra(MGraph G , int v , int path[] , int dist[]){
bool vis[Maxsize]; //那些被访问最短路径,访问过的设置为true , 未访问的false
int u;
//初始化记录表
for(int i = 0 ; i < G.vexnum ; i ++){
dist[i] = G.edge[v][i]; // 到初始的结点的距离
vis[i] = false; // 所有的结点都是尚未访问的
if(G.edge[v][i] < INF)
path[i] = v; // 与初始结点联通的数据写入path
else
path[i] = -1
}
vis[v] = true; // 根结点已经访问过
path[v] = -1;
//核心
for(int i = 0 ; i < G.vexnum ; i ++){
int min = INF;
//核心:找最小值
for(int j = 0 ; j < G.vexnum ; j ++){
if(vis[j] == false && dist[j] < min){ //找未访问过的结点中的最小值
min = dist[j];
u = j;
}
}
//核心:更新数组
vis[u] = true; // 该结点访问过
for(int j = 0 ; j < G.vexnum ; j ++){
if(vis[j] == false && dist[u] + G.edges[u][j] < dist[j]){ // 找那些能与当前结点
dist[j] = dist[j] + G.edges[u][j];
path[j] = u; // 更新,代表这条路径的来源
}
}
}
}
Floyd算法
void Floyd(MGraph G , int Path[][]){
int A[Maxsize][Maxsize];
//初始化
for(int i = 0 ; i < G.vexnums ; i ++){
for(int j = 0 ; j < G.vexnums ; j ++){
A[i][j] = G.Edges[i][j];
Path[i][j] = -1;
}
}
//更新数值
for(int k = 0 ; k < G.vexnums; k ++){
for(int i = 0 ; i < G.vexnums ; i ++){
for(int j = 0 ; j < G.vexnums ; j ++){
if(A[i][j] > A[i][k] + A[k][j]){ // 从 i 到 k 到 j 的距离 < i 到 j 的距离
A[i][j] = A[i][k] + A[k][j];
Path[i][j] = k; // 中间穿插的路径
}
}
}
}
}
拓扑排序
若是三角矩阵,有拓扑序列。形不成环。
bool TopologicalSort(Graph G){
stack<int> s;
//找到一个入度为 0 的结点
for(int i = 0 ; i < G.vexnum ; i ++){
if(indrgee[i] == 0){
s.push(i);
}
}
int count = 0; // 记录当前已经输出的顶点数
while(!s.empty()){
int k = s.top();
s.pop();
count ++;
printf("%d " , G.adlist[k]);
for(ArcNode *p = G.vertices[i].firstarc ; p ; p = p->nextarc){ //遍历这个结点的孩子链表
v = p->adjvex;
if(!( --indegree[v])) // 如果它的结点的数值减到 0 了 入栈
s.push(v);
}
}
if(count < G.vexnum) // 输出的结点数比原来的少,则存在回路
return false; // 有环的话,入度结点不肯能有1 -> 栈空了 -> count的个数不如原有的多
else
return true;
}