十、不相交集
访问 www.coding-time.cn 阅读原文动画效果,体验更佳。
不相交集数据结构(也称为并查集或者合并-查找集)是一种跟踪一组元素划分为许多不相交(非重叠)子集的数据结构。它提供近乎常数时间的操作(受到阿克曼函数的限制)来添加新集合,合并现有集合,以及确定元素是否在同一集合中。除了许多其他用途(见应用部分),不相交集在 Kruskal's 算法中起着关键作用,该算法用于查找图的最小生成树。
MakeSet 创建了 8 个单元素集合。
在进行了一些 Union 操作之后,一些集合被组合在一起。
1. 完整代码
DisjointSetItem
export default class DisjointSetItem { /** * @param {*} value * @param {function(value: *)} [keyCallback] */ constructor(value, keyCallback) { // 存储元素值 this.value = value; // 键回调函数用于生成键 this.keyCallback = keyCallback; // 父元素,默认为 null this.parent = null; // 子元素,初始为空对象 this.children = {}; } /** * @return {*} */ getKey() { // 允许用户定义自定义键生成器。 if (this.keyCallback) { return this.keyCallback(this.value); } // 否则,默认使用 value 作为键。 return this.value; } /** * @return {DisjointSetItem} */ getRoot() { // 如果当前元素是根元素,返回自身,否则返回父元素的根。 return this.isRoot() ? this : this.parent.getRoot(); } /** * @return {boolean} */ isRoot() { // 如果 parent 为 null,则当前元素为根元素 return this.parent === null; } /** * Rank基本上意味着所有祖先的数量。 * * @return {number} */ getRank() { // 如果没有子元素,rank 为 0 if (this.getChildren().length === 0) { return 0; } let rank = 0; /** @var {DisjointSetItem} child */ this.getChildren().forEach((child) => { // 计算子节点本身。 rank += 1; // 也添加当前子节点的所有子节点。 rank += child.getRank(); }); return rank; } /** * @return {DisjointSetItem[]} */ getChildren() { // 返回所有子元素 return Object.values(this.children); } /** * @param {DisjointSetItem} parentItem * @param {boolean} forceSettingParentChild * @return {DisjointSetItem} */ setParent(parentItem, forceSettingParentChild = true) { // 设置父元素 this.parent = parentItem; // 如果 forceSettingParentChild 为 true,则把当前元素添加到父元素的子元素中 if (forceSettingParentChild) { parentItem.addChild(this); } return this; } /** * @param {DisjointSetItem} childItem * @return {DisjointSetItem} */ addChild(childItem) { // 将元素添加到子元素 this.children[childItem.getKey()] = childItem; // 将当前元素设置为添加的元素的父元素 childItem.setParent(this, false); return this; }}
带你读《图解算法小抄》十、不相交集(2)https://developer.aliyun.com/article/1348196?groupCode=tech_library