Making a “good” maze
Disjoint Set Union/Find ADT
Up-trees
Represent maze environment as graph
{V,E}
 collection of rooms: V connections between rooms (initially all closed): E
Construct a maze:
 collection of rooms: V = V
 designated rooms in, iV, and out, oV
 collection of connections to knock down: E  E
 So far, some walls have been
knocked down while others remain.
 Now, we consider the wall
between A and B.
 Should we knock it down?
no
, if A and B
are
otherwise connected
yes
, if A and B
are not
otherwise connected
A
While edges remain in E
Remove a random edge
e = (u, v)from
E If
uand
vhave not yet been connected
- add e to E
An equivalence relation R has three properties:
 refexive: for any x, xRx is true
 symmetric: for any x and y, xRy implies yRx
 transitive: for any x, y, and z, xRy and yRz implies xRz
Connection between rooms is an equivalence relation (call it C) For any rooms a, b, c
a C a (A room connects to itself!) If a C b, then b C a
If a C b and b C c, then a C c
Union/Find ADT operations
 union  fnd  create  destroy
Disjoint set equivalence property: every element of a DS U/F structure belongs to exactly one set
Dynamic equivalence property: the set of an element
can change after execution of a union
{1,4,8}
{7}
{6}
{5,9,10}
{2,3} find(4)
8
union(2,6)
Given a set U = {a1, a2, … , an}
 Maintain a partition of U, a set of subsets of U {S1, S2, … ,
Sk} such that:
- each pair of subsets S
i and Sj are disjoint:
- together, the subsets cover U:
- The S
i are mutually exclusive and collectively exhaustive
 Union(a, b) creates a new subset which is the union of a’s subset and b’s subset
NOTE: outside agent decides when/what to union - ADT is just the bookkeeper
 Find(a) returns a unique name for a’s subset
NOTE: set names are arbitrary! We only care that:
Construct the maze on the right
Initial state (set names underlined):
{a}{b}{c}{d}{e}{f}{g}{h}{i}
Maze constructor (outside agent) traverses edges in random order and decides whether to union
{a}{b}{c}{d}{e}{f}{g}{h}
union(b, e)
{a}{b,e}{c}{d}{f}{g}{h}
Order of edges in blue
Finding the representative member of a set
is somewhat like the
opposite
of finding
whether a given item exists in a set.
 Each subset is an up-tree with its root as its representative member  All members of a given
set are nodes in that set’s up-tree
 Hash table maps input data to the node
associated with that data
a c g h
d b
e
Up-trees are not necessarily binary!
a c g h
d b
e
f i
find(f) find(e)
a
d
b
e
c
f
g h i
11
10
7
9 8
12
Just traverse to the root!
a c g h
d b
e
f i
union(a,c)
a
d
b
e
c
f
g h i
11
10
9 8
12
Just hang one root from the other!
find(d) = find(e) No union!
find(e)
find(e) = find(h) and find(b) = find(c) So, no unions for either of these.
a
d
b
e
c
f
g h i
11
10
9
12
f
g
h a
b
c
i d
find(g) = find(h) So, no union.
And, we’re done!
a
Ooh… scary!
 A forest of up-trees
can easily be
stored in an array.
 Also, if the node
names are integers or characters, we can use a very simple, perfect hash.
f
g h a
b
c
i d
e
0 -1 0 1 2 -1 -1 7
-1
0 (a) 1 (b) 2 (c) 3 (d) 4 (e) 5 (f) 6 (g) 7 (h) 8 (i)
up-index:
typedef ID int;
ID find(Object x) {
assert(hTable.contains(x)); ID xID = hTable[x];
while(up[xID] != -1) { xID = up[xID];
}
return xID; }
ID union(ID x, ID y) { assert(up[x] == -1); assert(up[y] == -1);
up[y] = x; }
 Simple ADT, simple data structure, simple code
 Complex complexity analysis, but extremely useful
result: essentially, constant time!
 Lots of potential applications
 Object-property collections
 Index partitions: e.g. parts inspection
 To say nothing of maze construction
 In some applications, it may make sense to have meaningful