本文介绍了一种高效实现并查集数据结构的方法,通过使用森林数据结构,并结合路径压缩和按秩联合策略来优化操作效率。并查集主要用于解决元素集合的合并及查询问题,文中提供了详细的 C 语言实现代码。
ref:http://en.literateprograms.org/Disjoint_set_data_structure_(C) The three main operations in disjoint set are: MakeSet: Create a new partition containing a single given element. Find: Figure out which partition a given element is in. Union: Merge two partitions into a single partition.
The most efficient known and most commonly used is disjoint set forests with path compression and the union rank heuristic
#include<iostream> #include <cstdlib> #include <cassert> usingnamespace std; //forest node typedef struct forest_node_t ...{ void* value; struct forest_node_t* parent; int rank; } forest_node; forest_node* MakeSet(void* value); forest_node* Find(forest_node* node); void Union(forest_node* node1, forest_node* node2); //find operation forest_node* Find(forest_node* node) ...{ forest_node* temp; /**//* Find the root */ forest_node* root = node; while (root->parent != NULL) ...{ root = root->parent; } /**//* Update the parent pointers */ while (node->parent != NULL) ...{ temp = node->parent; node->parent = temp; node = temp; } return root; } //union operation /**//* Given the root elements of two trees, merge the trees into one tree */ /**//* If rank(s) ≠ rank(t), then rank(Union(s,t)) is the larger of rank(s) and rank(t), we attach the tree with smaller rank to the root of the tree with larger rank. If rank(s) = rank(t), then rank(Union(s,t)) = rank(s) + 1 = rank(t) + 1. */ void Union(forest_node* node1, forest_node* node2) ...{ if (node1->rank > node2->rank) ...{ node2->parent = node1; }elseif (node2->rank > node1->rank) ...{ node1->parent = node2; }else...{ /**//* they are equal */ node2->parent = node1; node1->rank++; } } //Make-Set operation forest_node* MakeSet(void* value) ...{ forest_node* node = (forest_node*)malloc(sizeof(forest_node)); node->value = value; node->parent = NULL; /**//*MakeSet always produces a tree of rank 0: */ node->rank =0; return node; } int main() ...{ int i1=1, i2=2, i3=3; forest_node *s1=MakeSet(&i1), *s2=MakeSet(&i2), *s3=MakeSet(&i3); assert(Find(s1) == s1); Union(s1, s2); assert(Find(s1) == Find(s2)); assert(Find(s1) != Find(s3)); Union(s2, s3); assert(Find(s1) == Find(s2) && Find(s1) == Find(s3)); return0; }