#include<stdio.h>
#include<queue>
#include<stack>
#include<stdlib.h>
using namespace std;
typedef char VertexType;//頂點類型
typedef int EdgeType;//邊的權重
#define MAXVEX 100//最大頂點數
#define INFINITY 65535//代表無窮
#define MAXEDGE 1000
typedef struct
{
VertexType vexs[MAXVEX];//頂點表
EdgeType arc[MAXVEX][MAXVEX];//鄰接矩陣
int numVertexes,numEdges;//目前的頂點數和邊數
} MGraph;
拓撲排序&關鍵路徑
求拓撲排序的基本思想:
1)從有向圖中選 一個無前驅(入度為0)的頂點輸出;
2)将此頂點和以它為起點的孤删除;
3)重複1)和2), 直到不存在無前驅的頂點;
4)若此時輸出的頂點數小于有向圖中的頂點數,則說明有向圖中存在回路,否則輸出的頂點的順序即為一個拓撲序列。
typedef struct EdgeNode//邊表結點 (用于拓撲排序)
{
int adjvex;//鄰接頂點的下标
int weight;//權,用于關鍵路徑算法
struct EdgeNode *next;//指向下一個鄰接點
}EdgeNode;
typedef struct VertexNode//頂點表結點 (用于拓撲排序)
{
int in;//頂點的入度
int data;//頂點的值
EdgeNode *firstedge;//邊表的頭指針
}VertexNode,AdjList[MAXVEX];
typedef struct//(用于拓撲排序)
{
AdjList adjList;
int numVertexes,numEdges;//頂點數和邊數
}graphAdjList,*GraphAdjList;
//拓撲排序,若GL無回路則輸出拓撲排序序列并傳回true,否則傳回false
bool TopologicalSort(GraphAdjList GL)
{
EdgeNode *e;
int i,k,gettop,count=0;//gettop用于儲存出棧的數,count用于統計輸出頂點的個數
stack<int> s;
for(i=0;i<GL->numVertexes;i++)//将入度為0的頂點入棧
{
if(GL->adjList[i].in==0)s.push(i);
}
while(!s.empty())
{
gettop=s.top();
s.pop();
printf("%d -> ",GL->adjList[gettop].data);
count++;
for(e=GL->adjList[gettop].firstedge;e;e=e->next)
{
k=e->adjvex;
if(!(--GL->adjList[k].in))s.push(k);//若入度為0則入棧,友善下次循環輸出
}
}
if(count<GL->numVertexes)return false;//count<頂點數說明存在環
else return true;
}
int *etv,*ltv;//指向earliest time of vertex & latest time of vertex數組的指針
stack<int> s2;//用于儲存拓撲序列
//增加了一些代碼的拓撲排序,用于尋找關鍵路徑
//若GL無回路則輸出拓撲排序序列并傳回true,否則傳回false
bool TopologicalSort2(GraphAdjList GL)
{
EdgeNode *e;
int i,k,gettop,count=0;//gettop用于儲存出棧的數,count用于統計輸出頂點的個數
stack<int> s;
for(i=0;i<GL->numVertexes;i++)//将入度為0的頂點入棧
{
if(GL->adjList[i].in==0)s.push(i);
}
etv=(int*)malloc(GL->numVertexes*sizeof(int));//建立事件最早發生時間數組
for(i=0;i<GL->numVertexes;i++)etv[i]=0;//數組的初始化
while(!s.empty())
{
gettop=s.top();
s.pop();
count++;
s2.push(gettop);//将拓撲序列入棧
for(e=GL->adjList[gettop].firstedge;e;e=e->next)
{
k=e->adjvex;
if(!(--GL->adjList[k].in))s.push(k);//若入度為0則入棧,友善下次循環輸出
if(etv[gettop]+e->weight>etv[k])etv[k]=etv[gettop]+e->weight;
}
}
if(count<GL->numVertexes)return false;//count<頂點數說明存在環
else return true;
}
//尋找關鍵路徑
void CriticalPath(GraphAdjList GL)
{
EdgeNode* e;
int i,gettop,k,j;
int ete,lte;//earliest time of edge & latest time of edge
TopologicalSort(GL);
ltv=(int*)malloc(GL->numVertexes*sizeof(int));
for(i=0;i<GL->numVertexes;i++)ltv[i]=etv[GL->numVertexes-1];//數組的初始化
while(!s2.empty())
{
gettop=s2.top();
s2.pop();
for(e=GL->adjList[gettop].firstedge;e;e=e->next)
{
k=e->adjvex;
if(ltv[k]-e->weight<ltv[gettop])ltv[gettop]=ltv[k]-e->weight;
}
}
for(j=0;j<GL->numVertexes;j++)
{
for(e=GL->adjList[j].firstedge;e;e=e->next)
{
k=e->adjvex;
ete=etv[j];
lte=ltv[k]-e->weight;
if(ete==lte)
printf("<v%d-v%d> length:%d\n",GL->adjList[j].data,GL->adjList[k].data,e->weight);
}
}
}
最短路徑
typedef int Patharc[MAXVEX];//儲存最短路徑(用于Dijkstra算法尋找最短路徑)
typedef int ShortPathTable[MAXVEX];//儲存從起點到各點的最短路徑的權值和(用于Dijkstra算法尋找最短路徑)
typedef int Patharc1[MAXVEX][MAXVEX];//儲存最短路徑(用于Floyd算法尋找最短路徑)
typedef int ShortPathTable1[MAXVEX][MAXVEX];//儲存從起點到各點的最短路徑的權值和(用于Floyd算法尋找最短路徑)
//Floyd算法求最短路徑
void ShortestPath_Floyd(MGraph *G,Patharc1 *P,ShortPathTable1 *D)
{
int v,w,k;
for(v=0;v<G->numVertexes;v++)//初始化D和P
{
for(w=0;w<G->numVertexes;w++)
{
(*D)[v][w]=G->arc[v][w];
(*P)[v][w]=w;
}
}
for(k=0;k<G->numVertexes;k++)//k為中轉頂點的下标
{
for(v=0;v<G->numVertexes;v++)//v為起點
{
for(w=0;w<G->numVertexes;w++)//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];
}
}
}
}
//列印最短路徑
printf("各頂點間最短路徑如下:\n");
for(v=0;v<G->numVertexes;v++)
{
for(w=v+1;w<G->numVertexes;w++)
{
printf("v%d-v%d weight:%d",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);//列印終點
}
printf("\n");
}
}
//Dijkstra算法求最短路徑及相應的長度
//*P[v]為前驅點下标,D[v]表示從v0到v的最短路徑長度
void ShortestPath_Dijkstra(MGraph *G,int v0,Patharc P,ShortPathTable D)
{
int v,w,k,min;
int final[MAXVEX];//final[w]=1 表示已經求得v0和vw的最短路徑
for(v=0;v<G->numVertexes;v++)//初始化
{
final[v]=0;//全部頂點初始化為未知最短路徑狀态
D[v]=G->arc[v0][v];//将與v0有連線的頂點加上權值
P[v]=-1;//初始化路徑數組為-1
}
D[v0]=0;
final[v0]=1;
//每次循環求得起點v0到頂點V的最短路徑
for(v=1;v<G->numVertexes;v++)
{
min=INFINITY;
for(w=0;w<G->numVertexes;w++)//尋找離v0最近且尚未找到最短路徑的頂點
{
if(!final[w]&&D[w]<min)
{
k=w;
min=D[w];
}
}
final[k]=1;
for(w=0;w<G->numVertexes;w++)///修正目前的最短路徑及距離
{
if(!final[w]&&(min+G->arc[k][w]<D[w]))
{
D[w]=min+G->arc[k][w];
P[w]=k;
}
}
}
}
最小生成樹
//Prim算法生成最小生成樹
void MiniSpanTree_Prim(MGraph *G)
{
int min,i,j,k;
int adjvex[MAXVEX];//儲存相關頂點間邊的權值點下标
int lowcost[MAXVEX];//儲存相關頂點間邊的權值
lowcost[0]=0;//初始化第一個權值為0,即将v0加入生成樹
adjvex[0]=0;//初始化第一個頂點下标為0
for(i=1;i<G->numNodes;i++)//周遊除下标為0外的所有頂點
{
lowcost[i]=G->arc[0][i];//v0與其他頂點的權值存入數組
adjvex[i]=0;//初始化都為v0的下标 ?????
}
for(i=1;i<G->numNodes;i++)
{
min=INFINITY;
j=1;k=0;
while(j<G->numNodes)//整個while循環的作用:找到與已聯通結點相連的、不會形成環路的最短邊
{
if(lowcost[j]!=0&&lowcost[j]<min)//若權值不為0且小于min
{
min=lowcost[j];//則讓目前權值成為最小值
k=j;// 并将其下标存入k
}
j++;
}
printf("(%d,%d)\n",adjvex[k],k);//列印目前頂點的邊中權最小的那條
lowcost[k]=0;//将目前頂點權設為0,表示此頂點已經完成任務
for(j=1;j<G->numNodes;j++)
{
if(lowcost[j]!=0&&G->arc[k][j]<lowcost[j])//若下标為k的頂點的各邊權值小于這些頂點未被加入生成樹時的權值
{
lowcost[j]=G->arc[k][j];//将較小的權值存入lowcost相應位置
adjvex[j]=k;//将下标為k的頂點存入adjvex
}
}
}
}
typedef struct //邊集數組 (用于Kruskal算法)
{
int begin;
int end;
int weight;
}Edge;
//(用于Kruskal算法)查找連線頂點的尾部下标
int Find(int *parent,int f)
{
while(parent[f]>0)
{
f=parent[f];
}
return f;
}
//Kruskal算法生成最小生成樹
void MiniSpanTree_Kruskal(MGraph *G)
{
int i,n,m;
Edge edges[MAXEDGE];//邊集數組,其中的元素按照權值從小到大排序
int parent[MAXVEX];//判斷邊與邊是否形成回路,下标和儲存的值分别代表邊的起點和終點
//省略将鄰接矩陣轉換為邊集數組并排序的過程
for(i=0;i<G->numNodes;i++)
parent[i]=0;//初始化
for(i=0;i<G->numEdges;i++)
{
n=Find(parent,edges[i].begin);
m=Find(parent,edges[i].end);
if(n!=m)//n!=m說明此邊沒有和現有的生成樹形成環路
{
parent[n]=m;//将結尾頂點放入下标為起點的parent中,表示該邊已經在生成樹裡
printf("(%d,%d) %d\n",edges[i].begin,edges[i].end,edges[i].weight);
}
}
}
DFS(深度優先搜尋 )&BFS(廣度優先搜尋)
bool visited[MAXVEX];//記錄結點是否被通路過 (用于DFS&BFS)
void DFS(MGraph *G,int i)
{
int j;
visited[i]=true;
printf("%c ",G->vexs[i]);
for(j=0;j<G->numNodes;j++)
{
if(G->arc[i][j]==1&&!visited[j])
DFS(G,j);
}
}
void DFSTraverse(MGraph *G)
{
int i;
for(i=0;i<G->numNodes;i++)
visited[i]=false;
for(i=0;i<G->numNodes;i++)//如果是連通圖則本循環隻執行一次
if(!visited[i]) DFS(G,i);
}
void BFSTraverse(MGraph *G)
{
int i,j;
queue <int> Q;
for(i=0;i<G->numNodes;i++)
visited[i]=false;
Q.pop();
for(i=0;i<G->numNodes;i++)
{
if(!visited[i])
{
visited[i]=true;
printf("%c ",G->vexs[i]);
Q.push(i);
while(!Q.empty())
{
Q.pop();
for(j=0;j<G->numNodes;j++)
{
if(G->arc[i][j]==1&&!visited[j])
{
visited[j]=true;
printf("%c ",G->vexs[j]);
Q.push(j);
}
}
}
}
}
}
建立無向圖的鄰 接矩陣
//建立無向圖的鄰接矩陣
void CreateMGragh(MGraph *G)
{
int i,j,k,w;
printf("依次輸入頂點數和邊數:\n");
scanf("%d %d",&G->numNodes,&G->numEdges);
for(i=0;i<G->numNodes;i++)
scanf(&G->vexs[i]);//建立頂點表
//上面這行看不懂
for(i=0;i<G->numNodes;i++)
for(j=0;j<G->numNodes;j++)
G->arc[i][j]=INFINITY;//鄰接矩陣初始化
for(k=0;k<G->numNodes;k++)
{
printf("輸入邊(vi,vj)的下标i,下标j和權w,中間用空格分隔:\n");
scanf("%d %d %d",&i,&j,&w);
G->arc[i][j]=w;
G->arc[j][i]=w;
}
}
聯系之前的文章:廣度優先搜尋(BFS)尋找最短路徑_mirrorboat的部落格-CSDN部落格#include<iostream>using namespace std;void EnQueue(int i, int j, int k); //入隊一個節點void DeQueue(int* i, int* j, int* k); //擷取目前節點的序号和對應的迷宮坐标,然後出列int GetNextPos(int* i, int* j, int count); //得到下一個鄰接點的位置void ShortestPath_BFS(int i, int j); //廣度優先遍.
https://blog.csdn.net/mirrorboat/article/details/122638680?spm=1001.2014.3001.5502