Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/networkx/utils/union_find.py: 18%
39 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-10-20 07:00 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-10-20 07:00 +0000
1"""
2Union-find data structure.
3"""
5from networkx.utils import groups
8class UnionFind:
9 """Union-find data structure.
11 Each unionFind instance X maintains a family of disjoint sets of
12 hashable objects, supporting the following two methods:
14 - X[item] returns a name for the set containing the given item.
15 Each set is named by an arbitrarily-chosen one of its members; as
16 long as the set remains unchanged it will keep the same name. If
17 the item is not yet part of a set in X, a new singleton set is
18 created for it.
20 - X.union(item1, item2, ...) merges the sets containing each item
21 into a single larger set. If any item is not yet part of a set
22 in X, it is added to X as one of the members of the merged set.
24 Union-find data structure. Based on Josiah Carlson's code,
25 https://code.activestate.com/recipes/215912/
26 with significant additional changes by D. Eppstein.
27 http://www.ics.uci.edu/~eppstein/PADS/UnionFind.py
29 """
31 def __init__(self, elements=None):
32 """Create a new empty union-find structure.
34 If *elements* is an iterable, this structure will be initialized
35 with the discrete partition on the given set of elements.
37 """
38 if elements is None:
39 elements = ()
40 self.parents = {}
41 self.weights = {}
42 for x in elements:
43 self.weights[x] = 1
44 self.parents[x] = x
46 def __getitem__(self, object):
47 """Find and return the name of the set containing the object."""
49 # check for previously unknown object
50 if object not in self.parents:
51 self.parents[object] = object
52 self.weights[object] = 1
53 return object
55 # find path of objects leading to the root
56 path = []
57 root = self.parents[object]
58 while root != object:
59 path.append(object)
60 object = root
61 root = self.parents[object]
63 # compress the path and return
64 for ancestor in path:
65 self.parents[ancestor] = root
66 return root
68 def __iter__(self):
69 """Iterate through all items ever found or unioned by this structure."""
70 return iter(self.parents)
72 def to_sets(self):
73 """Iterates over the sets stored in this structure.
75 For example::
77 >>> partition = UnionFind("xyz")
78 >>> sorted(map(sorted, partition.to_sets()))
79 [['x'], ['y'], ['z']]
80 >>> partition.union("x", "y")
81 >>> sorted(map(sorted, partition.to_sets()))
82 [['x', 'y'], ['z']]
84 """
85 # Ensure fully pruned paths
86 for x in self.parents:
87 _ = self[x] # Evaluated for side-effect only
89 yield from groups(self.parents).values()
91 def union(self, *objects):
92 """Find the sets containing the objects and merge them all."""
93 # Find the heaviest root according to its weight.
94 roots = iter(
95 sorted(
96 {self[x] for x in objects}, key=lambda r: self.weights[r], reverse=True
97 )
98 )
99 try:
100 root = next(roots)
101 except StopIteration:
102 return
104 for r in roots:
105 self.weights[root] += self.weights[r]
106 self.parents[r] = root