1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%% NONDESTRUCTIVE UNION-FIND
5
%% Union-find with path compression; requires a fixed number of
6
%% equivalence classes to be merged. This implementation will create
7
%% new versions of the datastructures.
9
%% init(N): initializes N equivalence classes with self as value
10
%% (i.e., class N has value N)
11
%% list(U): list the {Index,EquivClass} pairs of U
12
%% union(X,Y,U): merge equivalence classes X and Y (must be integers!)
13
%% find(X,U): returns {Value,NewU}
14
%% only_find(X,U): returns Index (no path compression is done)
16
-module(hipe_pure_ufind).
23
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
26
list_to_tuple(mklist(1,N)).
28
mklist(M,N) when M > N -> [];
29
mklist(M,N) -> [M|mklist(M+1,N)].
31
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
34
list_all(1,size(U),U).
36
list_all(M,N,_U) when M > N ->
40
[{M,V}|list_all(M+1,N,NewU)].
42
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
44
%% Equivalence classes are represented as a vector of integers.
45
%% Initially, each position i has the value i, but as classes are
46
%% merged, i will get value j, j value k, etc.
47
%% Find traces such a chain until it finds an index i with value i;
48
%% this is the true value.
49
%% Union merges two classes by dereferencing both, then
50
%% setting one to point to the other.
52
%% Note: there must _never_ be nontrivial circular chains x -> y -> ... -> x
53
%% or the algorithm will loop!
54
%% This is the reason for doing 'find' on both elements in union.
55
%% A second method is given as union2/3, which is slightly more complex
56
%% but sometimes avoids an extra find-operation.
58
%% I haven't measured which one is the fastest in practice.
61
%% - dereference chain of indices until a self-pointer occurs.
65
X -> % returned self: chain ended
67
Y -> % returned other: follow chain
69
{V,setelement(X,NewU,V)}
74
X -> % returned self: end of chain
80
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
82
% Two implementations of the UNION operation.
90
% - Always dereference both arguments. The 'end-points' equivalence
91
% classes can then be joined arbitrarily. (Either can point to the other.)
93
% COMMENTED OUT: Currently unused
96
% {V,NxtU} = find(X,U),
97
% {W,NewU} = find(Y,NxtU),
98
% setelement(V,NewU,W).
103
% - Always set a larger index to point to a smaller one. This avoids
104
% nontrivial circular chains and sometimes requires only one find.
107
% - first deref X to V. If V is larger than Y, it can safely point to Y
108
% (since Y won't point to anything as large as V)
109
% - otherwise, deref Y to W and set the larger of V or W to point to the
113
{V,NxtU} = find(X,U),
115
setelement(V,NxtU,Y);
117
{W,NewU} = find(Y,NxtU),
119
setelement(W,NewU,V);
121
setelement(V, NewU,W);