分析
最小生成树的克鲁斯卡尔(Kruskal)算法实现主要是通过将输入的图的边存在优先队列中,然后依次从优先队列中取最小的边加入生成树,最小生成树的边的个数是顶点数减一,因此退出条件是while (!pq.empty() || cnt < n - 1),其中需要注意的是在定义边结点EdgeNode时需要重载运算符<,因为在优先队列priority_queue中的实现逻辑就是需要比较元素的大小,那么在自定义结构体中则需要重载该运算符。 另外一个知识点就是并查集,这个数据结构的实现方式比较简单,类似于树的实现方式,具体知识可参考资料。总的来说,Kruskal算法的实现还是相对简单的。
C/C++代码实现
#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
;
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;
}
}
void UnionFind
::Union(const int& p
, const int& q
)
{
int x
= Find(p
);
int y
= Find(q
);
if (x
!= y
)
{
prev_
[y
] = x
;
}
}
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)
{
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. 加入边(2,5); 边长为3. 加入边(3,6); 边长为4. 加入边(2,3); 边长为5.