前言
最近,需要用C++实现一个简单的disjoint set,查了一下STL,貌似没有已经做好的库,但是boost有。于是我决定测试一下。
测试系统是Ubuntu 18.04 LTS,gcc 7.5.0,boost 1.65.01。
Boost 的disjoint set documentation在
https://www.boost.org/doc/libs/1_72_0/libs/disjoint_sets/disjoint_sets.html
测试样例来自于这个教程
https://www.geeksforgeeks.org/kruskals-minimum-spanning-tree-algorithm-greedy-algo-2/
部分代码结构来自于这个SO提问
https://stackoverflow.com/questions/4134703/understanding-boostdisjoint-sets
经过
样例简单描述是这样的。我们有一个graph,所有edge都有一个weight,edge列表已经根据weight进行了升序排序,我们的目的是需要从这个graph中找到minimum spanning tree(MST)。所用的方法是Kruskal’s Minimum Spanning Tree Algorithm。graph的具体定义和算法描述都在教程中,这里复现一下教程的原图。
图 1. 教程graph原图。vertex上的数字是index。edge上的数字是weight而 不是 index。版权归原作者所有。
算法原理就是利用disjoint set。从最小weight的edge开始处理,对于一个新的edge E,找出E的两个vertex在disjoint set D中对应的子集。如果两个vertex在相同子集S内,那么向当前的MST中加入E之后将在S内形成一个circle,此时放弃向MST添加E。如果两个vertex在不同的子集中,那么将这两个子集union成新的子集,更新disjoint set D,并向MST中添加E。MST中最多可存在nv-1个edge,其中nv是原始vertex数。
经过Kruskal’s Minimum Spanning Tree Algorithm处理后,所得到的MST如下图所示。
图 2. 教程中MST的结果。版权归原作者所有。
根据上述问题的设定,我整了一个简单的代码,其中disjoint set部分是boost实现的。
//
// Created by yaoyu on 3/19/20.
//
#include <map>
#include <iostream>
#include <vector>
#include <boost/pending/disjoint_sets.hpp>
template <typename vertexIndexT, typename weightT>
class Edge
{
public:
// Default constructor.
Edge() = default;
// Constructor with vertex indices.
Edge(const vertexIndexT& v0, const vertexIndexT& v1, const weightT& w) {
mV0 = v0;
mV1 = v1;
mW = w;
}
// Copy constructor.
Edge(const Edge<vertexIndexT, weightT>& other) {
this->mV0 = other.mV0;
this->mV1 = other.mV1;
this->mW = other.mW;
}
~Edge() = default;
// Overload operator =.
Edge<vertexIndexT, weightT>& operator = (const Edge<vertexIndexT, weightT>& other) {
if ( this != &other ) {
this->mV0 = other.mV0;
this->mV1 = other.mV1;
this->mW = other.mW;
}
return *this;
}
// Overload the stream operator <<.
friend std::ostream& operator << (std::ostream& out, const Edge<vertexIndexT, weightT>& e) {
out << "Edge( "
<< e.mW << ", "
<< e.mV0