Disjoint-set data structure#

The main entry point is DisjointSet() which chooses the appropriate type to return. For more on the data structure, see DisjointSet().

This module defines a class for mutable partitioning of a set, which cannot be used as a key of a dictionary, vertex of a graph etc. For immutable partitioning see SetPartition.

AUTHORS:

  • Sébastien Labbé (2008) - Initial version.

  • Sébastien Labbé (2009-11-24) - Pickling support

  • Sébastien Labbé (2010-01) - Inclusion into sage (github issue #6775).

EXAMPLES:

Disjoint set of integers from 0 to n - 1:

sage: s = DisjointSet(6)
sage: s
{{0}, {1}, {2}, {3}, {4}, {5}}
sage: s.union(2, 4)
sage: s.union(1, 3)
sage: s.union(5, 1)
sage: s
{{0}, {1, 3, 5}, {2, 4}}
sage: s.find(3)
1
sage: s.find(5)
1
sage: list(map(s.find, range(6)))
[0, 1, 2, 1, 2, 1]

Disjoint set of hashables objects:

sage: d = DisjointSet('abcde')
sage: d
{{'a'}, {'b'}, {'c'}, {'d'}, {'e'}}
sage: d.union('a','b')
sage: d.union('b','c')
sage: d.union('c','d')
sage: d
{{'a', 'b', 'c', 'd'}, {'e'}}
sage: d.find('c')
'a'
sage.sets.disjoint_set.DisjointSet(arg)#

Constructs a disjoint set where each element of arg is in its own set. If arg is an integer, then the disjoint set returned is made of the integers from 0 to arg - 1.

A disjoint-set data structure (sometimes called union-find data structure) is a data structure that keeps track of a partitioning of a set into a number of separate, nonoverlapping sets. It performs two operations:

  • find() – Determine which set a particular element is in.

  • union() – Combine or merge two sets into a single set.

REFERENCES:

INPUT:

  • arg – non negative integer or an iterable of hashable objects.

EXAMPLES:

From a non-negative integer:

sage: DisjointSet(5)
{{0}, {1}, {2}, {3}, {4}}

From an iterable:

sage: DisjointSet('abcde')
{{'a'}, {'b'}, {'c'}, {'d'}, {'e'}}
sage: DisjointSet(range(6))
{{0}, {1}, {2}, {3}, {4}, {5}}
sage: DisjointSet(['yi',45,'cheval'])
{{'cheval'}, {'yi'}, {45}}
class sage.sets.disjoint_set.DisjointSet_class#

Bases: SageObject

Common class and methods for DisjointSet_of_integers and DisjointSet_of_hashables.

cardinality()#

Return the number of elements in self, not the number of subsets.

EXAMPLES:

sage: d = DisjointSet(5)
sage: d.cardinality()
5
sage: d.union(2, 4)
sage: d.cardinality()
5
sage: d = DisjointSet(range(5))
sage: d.cardinality()
5
sage: d.union(2, 4)
sage: d.cardinality()
5
number_of_subsets()#

Return the number of subsets in self.

EXAMPLES:

sage: d = DisjointSet(5)
sage: d.number_of_subsets()
5
sage: d.union(2, 4)
sage: d.number_of_subsets()
4
sage: d = DisjointSet(range(5))
sage: d.number_of_subsets()
5
sage: d.union(2, 4)
sage: d.number_of_subsets()
4
class sage.sets.disjoint_set.DisjointSet_of_hashables#

Bases: DisjointSet_class

Disjoint set of hashables.

EXAMPLES:

sage: d = DisjointSet('abcde')
sage: d
{{'a'}, {'b'}, {'c'}, {'d'}, {'e'}}
sage: d.union('a', 'c')
sage: d
{{'a', 'c'}, {'b'}, {'d'}, {'e'}}
sage: d.find('a')
'a'
element_to_root_dict()#

Return the dictionary where the keys are the elements of self and the values are their representative inside a list.

EXAMPLES:

sage: d = DisjointSet(range(5))
sage: d.union(2,3)
sage: d.union(4,1)
sage: e = d.element_to_root_dict()
sage: sorted(e.items())
[(0, 0), (1, 4), (2, 2), (3, 2), (4, 4)]
sage: WordMorphism(e)                                                       # needs sage.combinat
WordMorphism: 0->0, 1->4, 2->2, 3->2, 4->4
find(e)#

Return the representative of the set that e currently belongs to.

INPUT:

  • e – element in self

EXAMPLES:

sage: e = DisjointSet(range(5))
sage: e.union(4,2)
sage: e
{{0}, {1}, {2, 4}, {3}}
sage: e.find(2)
4
sage: e.find(4)
4
sage: e.union(1,3)
sage: e
{{0}, {1, 3}, {2, 4}}
sage: e.find(1)
1
sage: e.find(3)
1
sage: e.union(3,2)
sage: e
{{0}, {1, 2, 3, 4}}
sage: [e.find(i) for i in range(5)]
[0, 1, 1, 1, 1]
sage: e.find(5)
Traceback (most recent call last):
...
KeyError: 5
root_to_elements_dict()#

Return the dictionary where the keys are the roots of self and the values are the elements in the same set.

EXAMPLES:

sage: d = DisjointSet(range(5))
sage: d.union(2,3)
sage: d.union(4,1)
sage: e = d.root_to_elements_dict()
sage: sorted(e.items())
[(0, [0]), (2, [2, 3]), (4, [1, 4])]
to_digraph()#

Return the current digraph of self where \((a,b)\) is an oriented edge if \(b\) is the parent of \(a\).

EXAMPLES:

sage: d = DisjointSet(range(5))
sage: d.union(2,3)
sage: d.union(4,1)
sage: d.union(3,4)
sage: d
{{0}, {1, 2, 3, 4}}
sage: g = d.to_digraph(); g                                                 # needs sage.graphs
Looped digraph on 5 vertices
sage: g.edges(sort=True)                                                    # needs sage.graphs
[(0, 0, None), (1, 2, None), (2, 2, None), (3, 2, None), (4, 2, None)]

The result depends on the ordering of the union:

sage: d = DisjointSet(range(5))
sage: d.union(1,2)
sage: d.union(1,3)
sage: d.union(1,4)
sage: d
{{0}, {1, 2, 3, 4}}
sage: d.to_digraph().edges(sort=True)                                       # needs sage.graphs
[(0, 0, None), (1, 1, None), (2, 1, None), (3, 1, None), (4, 1, None)]
union(e, f)#

Combine the set of e and the set of f into one.

All elements in those two sets will share the same representative that can be gotten using find.

INPUT:

  • e – element in self

  • f – element in self

EXAMPLES:

sage: e = DisjointSet('abcde')
sage: e
{{'a'}, {'b'}, {'c'}, {'d'}, {'e'}}
sage: e.union('a','b')
sage: e
{{'a', 'b'}, {'c'}, {'d'}, {'e'}}
sage: e.union('c','e')
sage: e
{{'a', 'b'}, {'c', 'e'}, {'d'}}
sage: e.union('b','e')
sage: e
{{'a', 'b', 'c', 'e'}, {'d'}}
class sage.sets.disjoint_set.DisjointSet_of_integers#

Bases: DisjointSet_class

Disjoint set of integers from 0 to n-1.

EXAMPLES:

sage: d = DisjointSet(5)
sage: d
{{0}, {1}, {2}, {3}, {4}}
sage: d.union(2,4)
sage: d.union(0,2)
sage: d
{{0, 2, 4}, {1}, {3}}
sage: d.find(2)
2
element_to_root_dict()#

Return the dictionary where the keys are the elements of self and the values are their representative inside a list.

EXAMPLES:

sage: d = DisjointSet(5)
sage: d.union(2,3)
sage: d.union(4,1)
sage: e = d.element_to_root_dict(); e
{0: 0, 1: 4, 2: 2, 3: 2, 4: 4}
sage: WordMorphism(e)                                                       # needs sage.combinat
WordMorphism: 0->0, 1->4, 2->2, 3->2, 4->4
find(i)#

Return the representative of the set that i currently belongs to.

INPUT:

  • i – element in self

EXAMPLES:

sage: e = DisjointSet(5)
sage: e.union(4,2)
sage: e
{{0}, {1}, {2, 4}, {3}}
sage: e.find(2)
4
sage: e.find(4)
4
sage: e.union(1,3)
sage: e
{{0}, {1, 3}, {2, 4}}
sage: e.find(1)
1
sage: e.find(3)
1
sage: e.union(3,2)
sage: e
{{0}, {1, 2, 3, 4}}
sage: [e.find(i) for i in range(5)]
[0, 1, 1, 1, 1]
sage: e.find(5)
Traceback (most recent call last):
...
ValueError: i(=5) must be between 0 and 4
root_to_elements_dict()#

Return the dictionary where the keys are the roots of self and the values are the elements in the same set as the root.

EXAMPLES:

sage: d = DisjointSet(5)
sage: sorted(d.root_to_elements_dict().items())
[(0, [0]), (1, [1]), (2, [2]), (3, [3]), (4, [4])]
sage: d.union(2,3)
sage: sorted(d.root_to_elements_dict().items())
[(0, [0]), (1, [1]), (2, [2, 3]), (4, [4])]
sage: d.union(3,0)
sage: sorted(d.root_to_elements_dict().items())
[(1, [1]), (2, [0, 2, 3]), (4, [4])]
sage: d
{{0, 2, 3}, {1}, {4}}
to_digraph()#

Return the current digraph of self where \((a,b)\) is an oriented edge if \(b\) is the parent of \(a\).

EXAMPLES:

sage: d = DisjointSet(5)
sage: d.union(2,3)
sage: d.union(4,1)
sage: d.union(3,4)
sage: d
{{0}, {1, 2, 3, 4}}
sage: g = d.to_digraph(); g                                                 # needs sage.graphs
Looped digraph on 5 vertices
sage: g.edges(sort=True)                                                    # needs sage.graphs
[(0, 0, None), (1, 2, None), (2, 2, None), (3, 2, None), (4, 2, None)]

The result depends on the ordering of the union:

sage: d = DisjointSet(5)
sage: d.union(1,2)
sage: d.union(1,3)
sage: d.union(1,4)
sage: d
{{0}, {1, 2, 3, 4}}
sage: d.to_digraph().edges(sort=True)                                       # needs sage.graphs
[(0, 0, None), (1, 1, None), (2, 1, None), (3, 1, None), (4, 1, None)]
union(i, j)#

Combine the set of i and the set of j into one.

All elements in those two sets will share the same representative that can be gotten using find.

INPUT:

  • i – element in self

  • j – element in self

EXAMPLES:

sage: d = DisjointSet(5)
sage: d
{{0}, {1}, {2}, {3}, {4}}
sage: d.union(0,1)
sage: d
{{0, 1}, {2}, {3}, {4}}
sage: d.union(2,4)
sage: d
{{0, 1}, {2, 4}, {3}}
sage: d.union(1,4)
sage: d
{{0, 1, 2, 4}, {3}}
sage: d.union(1,5)
Traceback (most recent call last):
...
ValueError: j(=5) must be between 0 and 4