圖的最小生成樹Kruskal演算法樸素版(C++)
阿新 • • 發佈:2019-02-05
Kruskal演算法先將所有的邊按權值由小到大排序,然後從無開始(即每個頂點都是一棵子樹),每次選取權值最小又不會構成迴路的邊作為最終最小生成樹的一部分。最終能夠將多個不連通的子樹聯合起來構成最小生成樹。
時間複雜度為
C++程式碼如下:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef int DATA_TYPE; // 權值為int型
const DATA_TYPE NO_EDGE = 10000000 ; // 表示沒有該邊
// 鄰接矩陣
struct AdjMatrixGraph
{
vector<vector<DATA_TYPE> > weights;
};
// 邊和權值的配對 <<頭結點,尾結點>,權值>
typedef pair<vector<int>, DATA_TYPE> PAIR;
int comp(const PAIR &x, const PAIR &y)
{
return x.second < y.second;
}
vector<vector<int> > Kruskal(AdjMatrixGraph graph)
{
vector<vector<int> > MST; // 最小生成樹邊結果集合
int vertexNum = graph.weights.size(); // 頂點總數
vector<int> setNum; // 每個頂點所屬的子樹編號
vector<PAIR> edgesAndWeights; // 邊和權值配對的向量(便於按值排序)
for (int i = 0; i < vertexNum; ++i)
{
for (int j = 0; j < vertexNum; ++j)
{
if (graph.weights[i][j] > 0 && graph.weights[i][j] < NO_EDGE)
{
// 獲取每一條邊的資訊
edgesAndWeights.push_back(make_pair(vector<int>{i, j}, graph.weights[i][j]));
}
}
setNum.push_back(i); // 初始化每一個頂點都分屬不同的子樹
}
// 對每一條邊按權值升序排序
sort(edgesAndWeights.begin(), edgesAndWeights.end(), comp);
int k = 1; // 當前正在構造第幾條邊
// 最小生成樹總共有vertexNum-1條邊
for (vector<PAIR>::iterator mapIter = edgesAndWeights.begin(); mapIter != edgesAndWeights.end(); ++mapIter)
{
int headSet = setNum[mapIter->first[0]]; // 當前邊的頭結點所屬的子樹編號
int tailSet = setNum[mapIter->first[1]]; // 當前邊的尾結點所屬的子樹編號
// 如果它們分屬不同的子樹(即連線之後不構成迴路),則選擇該邊
if (headSet != tailSet)
{
MST.push_back(mapIter->first);
++k;
// 更新頂點的所屬子樹的編號
for (int i = 0; i < vertexNum; ++i)
{
if (setNum[i] == tailSet)
{
setNum[i] = headSet;
}
}
}
if (k >= vertexNum)
{
break;
}
}
return MST;
}
int main(int argc, char *argv[])
{
// 圖鄰接矩陣
// 編號從0開始 若不是先轉換
AdjMatrixGraph graph;
graph.weights.push_back(vector<DATA_TYPE>{0, 6, 1, 5, NO_EDGE, NO_EDGE});
graph.weights.push_back(vector<DATA_TYPE>{6, 0, 5, NO_EDGE, 3, NO_EDGE});
graph.weights.push_back(vector<DATA_TYPE>{1, 5, 0, 5, 6, 4});
graph.weights.push_back(vector<DATA_TYPE>{5, NO_EDGE, 5, 0, NO_EDGE, 2});
graph.weights.push_back(vector<DATA_TYPE>{NO_EDGE, 3, 6, NO_EDGE, 0, 6});
graph.weights.push_back(vector<DATA_TYPE>{NO_EDGE, NO_EDGE, 4, 2, 6, 0});
vector<vector<int> > MST = Kruskal(graph);
for (size_t i = 0; i < MST.size(); ++i)
{
cout <<"邊(" << MST[i][0] << " " << MST[i][1] << ") || 權值: " << graph.weights[MST[i][0]][MST[i][1]] << endl;
}
return 0;
}
測試用例圖如下:
輸出結果:
邊(0 2) || 權值: 1
邊(5 3) || 權值: 2
邊(4 1) || 權值: 3
邊(2 5) || 權值: 4
邊(2 1) || 權值: 5