分析する
最小スパニング ツリー ( ) の
MinSpanTree
KruskalKruskal
( ) アルゴリズムの実装は、主に、入力グラフのエッジを優先キューに格納し、優先キューから最小のエッジを取り出してスパニング ツリーに結合することによって行われます。最小スパニング ツリーでは、頂点の数から 1 を引いた値になるため、終了条件は になります。優先キューの実装ロジックはサイズを比較するため、while (!pq.empty() || cnt < n - 1)
エッジ ノードを定義するEdgeNode
ときに演算子をオーバーロードする必要があることに注意してください。要素のカスタム構造体で演算子をオーバーロードする必要があります。もう 1 つの知識ポイントは共用体検索です。このデータ構造の実装はツリーの実装と同様で比較的単純です。具体的な知識については資料を参照してください。一般に、クラスカルのアルゴリズムの実装は比較的単純です。<
priority_queue
C/C++ コードの実装
/*******************************************************
* Kruskal算法实现最小生成树
********************************************************/
#include<iostream>
#include<queue>
using namespace std;
const int maxn = 100;
int prev_[maxn];
int vexs[maxn];
int n;//顶点数
int m;//边数
struct EdgeNode {
int u, v;// u -> v
int weight;//边权值
/*对于常量型成员变量和引用型成员变量 此处成员变量都是普通成员变量 哪种方法初始化都行
必须通过初始化化列表的方式进行初始化
在构造函数体内进行赋值的方式是行不通的*/
EdgeNode(const int& u, const int& v, const int& weight) :u(u), v(v), weight(weight) {
}//构造函数
bool operator < (const EdgeNode& en) const {
return en.weight < this->weight; //最小值优先 建立堆元素升序排列
}
};
class UnionFind {
public:
UnionFind(const int& n);
int Find(const int& p);
void Union(const int& p, const int& q);
};
UnionFind::UnionFind(const int& n)
{
for (int i = 0; i < n; i++)
{
prev_[i] = -1;//父节点初始化为-1
}
}
void UnionFind::Union(const int& p, const int& q)
{
int x = Find(p); //找到p的祖先为x
int y = Find(q); //找到q的祖先为y
if (x != y)//不属于同一组
{
prev_[y] = x; //p, q 合并到一组
}
}
int UnionFind::Find(const int& p)
{
if (prev_[p] == -1)
return p;//找到祖先
return Find(prev_[p]);
}
int LocateVertex(int v)
{
for (int i = 0; i < n; i++)
{
if (v == vexs[i])
{
return i;
}
}
return -1;
}
void MinSpanTree_Kruskal(priority_queue<EdgeNode>& pq)
{
int cnt = 0;
UnionFind UF(n);
while (!pq.empty() || cnt < n - 1)//MST的边数为 顶点数 - 1
{
EdgeNode en = pq.top();
pq.pop();
int u = LocateVertex(en.u);//定位顶点索引
int v = LocateVertex(en.v);
int x = UF.Find(u);
int y = UF.Find(v);
if (x != y) //两个顶点不属于同一组
{
UF.Union(x, y);//合并两顶点
cnt++; //加入一条边
cout << "加入边(" << vexs[u] << "," << vexs[v] << "); 边长为" << en.weight << "." << endl;
}
}
}
int main()
{
int u[maxn];//起始点
int v[maxn];//终止点
int w[maxn];//权值
cout << "请输入顶点数(n >= 2):";
cin >> n;
cout << "请输入边数(m >= n - 1):";
cin >> m;
cout << "请输入边依附的顶点及权值信息:" << endl;
for (int i = 0; i < n; i++)
{
vexs[i] = i + 1;
}
priority_queue<EdgeNode> pq;
for (int i = 0; i < m; i++)
{
cin >> u[i] >> v[i] >> w[i];
EdgeNode en(u[i], v[i], w[i]);
pq.push(en);//建立小顶堆 边按权值进行升序排列
}
MinSpanTree_Kruskal(pq);
return 0;
}
出力結果
頂点の数を入力してください (n >= 2): 6
エッジの数を入力してください (m >= n - 1): 10
エッジが接続されている頂点とウェイト情報を入力してください:
1 2 6
1 3 1
1 4 5
2 3 5 2
5
3 3 4 5 3
5 6
5 6 6
3 6 4
4 6 2
辺(1,3)を結合します。辺の長さは 1 です。
辺(4,6)を結合します。辺の長さは 2 です。
join side(2,5) ; 辺の長さは 3.
join side(3,6); 辺の長さは 4.
join side(2,3); 辺の長さは 5.