理解 boost::disjoint_sets
我需要使用 boost::disjoint_sets,但是 文档 我不清楚。有人可以解释一下每个模板参数的含义,或者给出一个用于创建 disjoint_sets 的小示例代码吗?
根据请求,我使用 disjoint_sets 来实现 Tarjan 的离线最不常见祖先算法,即 -值类型应为 vertex_descriptor。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我从文档中可以理解的是:
不相交的需要将等级和父级(在林树中)与每个元素相关联。例如,由于您可能希望使用任何类型的数据,因此您并不总是希望对父级使用映射:对于整数,数组就足够了。您还需要每个元素的排名(并集查找所需的排名)。
您需要两个“属性”:
在一个示例中:
使用数组 < code>&rank[0], &parent[0] 到模板中的类型是
int*
对于更复杂的示例(使用地图),您可以查看 Ugo 的答案。
您只需为算法提供两个结构来存储他需要的数据(排名/父级)。
What I can understand from the documentation :
Disjoint need to associate a rank and a parent (in the forest tree) to each element. Since you might want to work with any kind of data you may,for example, not always want to use a map for the parent: with integer an array is sufficient. You also need a rank foe each element (the rank needed for the union-find).
You'll need two "properties" :
On an example :
Arrays are used
&rank[0], &parent[0]
to the type in the template isint*
For a more complex example (using maps) you can look at Ugo's answer.
You are just giving to the algorithm two structures to store the data (rank/parent) he needs.
find_with_full_path_compression
请参阅此处< /a> (默认值应该是您需要的)。示例:
请注意,“Boost 属性映射库包含一些适配器,用于转换实现映射操作的常用数据结构,例如内置数组(指针)、迭代器和 std::map,以具有属性映射接口”
这些适配器的列表(如 boost::associative_property_map)可以在 此处。
find_with_full_path_compression
See here (Default should be what you need).Example:
Note that "The Boost Property Map Library contains a few adaptors that convert commonly used data-structures that implement a mapping operation, such as builtin arrays (pointers), iterators, and std::map, to have the property map interface"
This list of these adaptors (like boost::associative_property_map) can be found here.
对于那些无法承受 std::map 的开销(或者因为类中没有默认构造函数而无法使用它)但数据又不那么简单的人作为
int
,我写了使用std::vector
解决方案的指南,当您事先知道元素总数时,这是最佳选择。该指南包含一个完整工作的示例代码,您可以使用它自行下载并测试。
那里提到的解决方案假设您可以控制类的代码,以便您可以添加一些属性。如果这仍然不可能,您总是可以在它周围添加一个包装器:
此外,如果您知道元素的数量很小,则不需要
size_t
,在这种情况下您可以添加一些模板对于UnsignedInt
类型,并在运行时决定使用uint8_t
、uint16_t
、uint32_t
或uint64_t 实例化它
,您可以通过
在 C++11 中或使用boost::cstdint
否则。如果您错过了,这里再次提供链接: http://janoma .cl/post/using-disjoint-sets-with-a-vector/
For those of you who can't afford the overhead of
std::map
(or can't use it because you don't have default constructor in your class), but whose data is not as simple asint
, I wrote a guide to a solution usingstd::vector
, which is kind of optimal when you know the total number of elements beforehand.The guide includes a fully-working sample code that you can download and test on your own.
The solution mentioned there assumes you have control of the class' code so that in particular you can add some attributes. If this is still not possible, you can always add a wrapper around it:
Moreover, if you know the number of elements to be small, there's no need for
size_t
, in which case you can add some template for theUnsignedInt
type and decide in runtime to instantiate it withuint8_t
,uint16_t
,uint32_t
oruint64_t
, which you can obtain with<cstdint>
in C++11 or withboost::cstdint
otherwise.Here's the link again in case you missed it: http://janoma.cl/post/using-disjoint-sets-with-a-vector/
Loic 的答案对我来说看起来不错,但我需要初始化父元素,以便每个元素都有自己作为父元素,因此我使用 iota 函数生成从 0 开始的递增序列。
使用 Boost,我为了简单起见,导入了bits/stdc++.h并使用了usingnamespacestd。
我将
std::vector
更改为std::array
因为将元素推送到向量将使其重新分配其数据,这使得不相交集对象包含的引用变得无效。据我所知,不能保证父级将是一个特定的数字,所以这就是为什么我写了
1或2或3或4
(可以是其中任何一个)。也许文档更详细地解释了哪个数字将被选为该组的领导者(我还没有研究过)。就我而言,输出是:
看起来很简单,它可能可以改进以使其更加健壮(以某种方式)。
注意:
std::iota
用顺序递增的值填充范围 [first, last),从 value 开始并重复评估 ++value。更多:https://en.cppreference.com/w/cpp/algorithm/iota
Loic's answer looks good to me, but I needed to initialize the parent so that each element had itself as parent, so I used the
iota
function to generate an increasing sequence starting from 0.Using Boost, and I imported
bits/stdc++.h
and usedusing namespace std
for simplicity.I changed
std::vector
tostd::array
because pushing elements to a vector will make it realloc its data, which makes the references the disjoint sets object contains become invalid.As far as I know, it's not guaranteed that the parent will be a specific number, so that's why I wrote
1 or 2 or 3 or 4
(it can be any of these). Maybe the documentation explains with more detail which number will be chosen as leader of the set (I haven't studied it).In my case, the output is:
Seems simple, it can probably be improved to make it more robust (somehow).
Note:
std::iota
Fills the range [first, last) with sequentially increasing values, starting with value and repetitively evaluating ++value.More: https://en.cppreference.com/w/cpp/algorithm/iota
我不久前写了一个简单的实现。看看吧。
用法是这样的。这很简单。不是吗?
I written a simple implementation a while ago. Have a look.
And the usage goes like this. It's simple. Isn't it?