一、算法描述
1.遍歷圖結構並初始化邊集合
2.初始化連通分支集合。每個連通分支集合初始化標誌元素指向自己
3.對邊集合從小到大排序
4.遍歷邊集合,判斷節點所屬連通分支是否相同。
5.如果4中判斷的連通分支不相同,輸出這條邊。執行4
說明:這裏採用鄰接矩陣方法儲存圖結構。
二、算法實現
void calculate_in_kruskal(MatGraph*gf)//Calculate minimum spanning tree
{
printf("\nKruskal:\n");
ENode edge[MAXMUM];//Edge set to selete the minimun edge
int ver[MAXMUM];//Vertex set pointing to the precurser
int k=0;
for(int i=0;i<gf->n;i++)//Go through all the elements in matgraph
for (int j = 0; j < gf->n; j++)
{
if (gf->edge[i][j] != -1)//Initialise all the edges in the graph
{
edge[k].n1 = i;
edge[k].n2 = j;
edge[k++].weight = gf->edge[i][j];
}
}
quicksort(edge,0,k);//Sort the edge set to select the minimum edge
for (int i = 0; i < gf->n; i++)//Initialise the vertex set and point it to itself
ver[i] = i;
int n1,n2;
for (int k = 0; k < 2*gf->e; k++)//Select the minimum edge in sequence
{
n1 = edge[k].n1;//n1 is the precurser of the kth edge
while (ver[n1] != n1)
n1 = ver[n1];
n2 = edge[k].n2;//n2 is the next vertex of the kth edge
while (ver[n2] != n2)
n2 = ver[n2];
if (n1 != n2)//If the kth edge has different vertexs
{
ver[n1] = n2;
printf("<%d,%d,%d>", edge[k].n1, edge[k].n2,edge[k].weight);
}
}
}
三、算法分析
首先分析Krustal算法的基本思路。算法採用貪心法的設計思想,從最小的邊開始,逐步依次選取更大的邊,直到遍歷完成所有的邊。每選一條邊,都要判斷邊的兩個鄰接點是否屬於同一個連通分支,換一句話說,判斷這條邊是否具有切分性質。如果屬於一個連通分支,那麼捨棄這條邊。算法的實現中採用並查集的策略判斷不同節點的集合標誌是否一樣。(算法正確性證明略去)
下面分析Krustal算法的時間複雜度。由算法描述可知,遍歷鄰接矩陣需要花費O(n^2)的漸進時間複雜度,把這一時間複雜度當做初始化過程不加以考慮。下面對邊集合的排序使用快速排序算法,軸點構造選用三者取中法,因此平均意義下時間複雜度爲O(e*loge)。當然,在這裏的排序算法是任意的,更常用的算法取的是堆排序,因爲堆排序更不容易退化爲O(n^2)的最壞時間複雜度。下面我們遍歷邊集合,需要O(e)的時間複雜度。因此,算法的時間複雜度爲O(e*loge).是一個複雜度僅與邊的數量有關的算法,適合於稀疏圖。
參考文獻
[1]曲婉玲等,算法設計與分析(第2版),2016.2
[2]李春葆,數據結構教程(第5版),2017.5