圖論
這篇文章介紹了幾種數據結構中圖的算法,最簡單的圖的搜索dfs和bfs,到高級圖的各種算法,如最小生成樹,最短路徑,關鍵路徑。
圖的存儲結構
typedef struct{
int arc[MAXVEX][MAXVEX];
int numVertexes,numEdges;
}MGraph;
最小生成樹Prim算法
這個算法的思想是從任意的一個根節點開始開始,一直長大到覆蓋圖中所有的節點爲止。這邊電腦演示比較麻煩,於是手寫演示。
void MiniSpanTree_Prim(MGraph G)
{
int min,i,j,k;
int adjvex[MAXVEX]; //保存相關頂點的下標
int lowcost[MAXVEX]; //保存頂點間的權值
lowcost[0] = 0;
adjvex[0] = 0;
for(i=0;i<G.numVertexes;i++)
{
lowcost[i] = G.arc[0][i]; //先將第一個頂點包含進去
adjvex[i] = 0;
}
for(i=1;i<G.numVertexes;i++)
{
min = INFINITY;
j = 1;k=0;
while(j<G.numEdges)
{
if(lowcost[j]!=0 && lowcost[j]<min) //選擇當前最小權值的大小和下標
{
min = lowcost[j];
k = j;
}
j++;
}
printf("(%d,%d)",adjvex[k],k); //輸出下標和相連的頂點
lowcost[k] = 0;
for(j=1;j<G.numVertexes;j++) //找與k相連的最小的權值的點。
{
if(lowcost[j] != 0 && G.arc[k][j]<lowcost[j])
{
lowcost[j] = G.arc[k][j];
adjvex[j] = k;
}
}
}
}
這個算法還要慢慢看。
Kruskal算法
除了上面的算法之外,還有一種我認爲更加經典的算法就是這個了。先貼代碼,再解釋。
typedef struct{
int begin;
int end;
int weight;
}Edge;
void Swapn(Edge *edges,int i,int j)
{
int temp;
temp = edges[i].begin;
edges[i].begin = edges[j].begin;
edges[j].begin = temp;
temp = edges[i].end;
edges[i].end = edges[j].end;
edges[j].end = temp;
temp = edges[i].weight;
edges[i].weight = edges[j].weight;
edges[j].weight = temp;
}
void sort(Edge edges[],MGraph *G)
{
int i,j;
for(i=0;i<G->numEdges;i++)
for(j=i+1;j<G->numEdges;j++)
if(edges[i].weight>edges[j].weight)
Swapn(edges,i,j);
}
int find(int *parent,int f)
{
while(parent[f]>0)
f = parent[f];
return f;
}
void MinSpanTree_Kruskal(MGraph G)
{
int i,j,n,m;
int k = 0;
int parent[MAXVEX];
Edge edges[MAXEDGE];
for(i=0;i<G.numVertexes;i++)
{
for(j=i+1;j<G.numVertexes;j++)
{
if(G.arc[i][j]<65535)
{
edges[k].begin = i;
edges[k].end = j;
edges[k].weight = G.arc[i][j];
k++;
}
}
}
sort(edges,&G);
for(i=0;i<G.numEdges;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)
{
parent[n] = m;
printf("%d %d %d\n",edges[i].begin,edges[i].end,edges[i].weight);
}
}
}
最短路徑
最短路徑需要解決的問題是求源點到各個點之間的最短路。這裏還分單源最短路徑和多源最短路徑。單源最短路徑算法就是Dijkstra算法,多源最短路徑是Floyd算法。
Dijkstra算法
void ShortPath_Dijkstra(MGraph G,int v0,Patharc *P,ShortPathTable *D)
{
int v,w,k,min;
int final[MAXVEX];
for(v=0;v<G.numVertexes;v++)
{
final[v] = 0;
(*D)[v] = G.arc[v0][v];
(*P)[v] = 0;
}
(*D)[v0] = 0;
final[v0] = 1;
for(v=1;v<G.numVertexes;v++)
{
min = INFINITY;
for(w = 0;w<G.numVertexes;w++)
{
if(!final[w] && (*D)[w] < min)
{
k = w;
min = (*D)[w];
}
}
final[k] = 1;
for(w=0;w<G.numEdges;w++)
{
if(!final[w] && (min + G.arc[k][w] < (*D)[w] ))
{
(*D)[w] = min + G.arc[k][w];
(*P)[w] = k;
}
}
}
}
應該代碼能夠看得懂的。
Floyd算法
void ShortPath_Floyd(MGraph G,Pathmatirx *P,ShortPathTable *D)
{
int v,w,k;
for(v=0;v<G.numVertexes;v++)
{
for(w=0;w<G.numVertexes;w++)
{
(*D)[v][w] = G.arc[v][w];
(*P)[v][w] = w;
}
}
for(k=0;v<G.numVertexes;k++)
{
for(v = 0;v<G.numVertexes;v++)
{
for(w = 0;w<G.numVertexes;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];
}
}
}
}
}
簡單粗暴吧。
今天終於將圖這部分算法搞懂了,以前一直想學卻沒有精力和毅力來學習。