mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2025-12-07 11:45:31 -05:00
imperative UnionFind structure
This commit is contained in:
parent
a9462cf06b
commit
1d476e3000
2 changed files with 201 additions and 0 deletions
116
unionFind.ml
Normal file
116
unionFind.ml
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
(*
|
||||
Copyright (c) 2013, Simon Cruanes
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer. Redistributions in binary
|
||||
form must reproduce the above copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other materials provided with
|
||||
the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*)
|
||||
|
||||
(** {1 Imperative Union-Find structure} *)
|
||||
|
||||
(** We need to be able to hash and compare keys, and values need to form
|
||||
a monoid *)
|
||||
module type PAIR = sig
|
||||
type key
|
||||
type value
|
||||
|
||||
val hash : key -> int
|
||||
val equal : key -> key -> bool
|
||||
|
||||
val merge : value -> value -> value
|
||||
val zero : value
|
||||
end
|
||||
|
||||
(** Build a union-find module from a key/value specification *)
|
||||
module Make(P : PAIR) = struct
|
||||
type key = P.key
|
||||
(** Elements that can be compared *)
|
||||
|
||||
type value = P.value
|
||||
(** Values associated with elements *)
|
||||
|
||||
type node = {
|
||||
mutable n_repr : key; (* representative *)
|
||||
mutable n_value : value; (* value (only up-to-date for representative) *)
|
||||
}
|
||||
|
||||
module H = Hashtbl.Make(struct include P type t = P.key end)
|
||||
|
||||
(** The union-find imperative structure itself*)
|
||||
type t = node H.t
|
||||
|
||||
let mk_node key = {
|
||||
n_repr = key;
|
||||
n_value = P.zero;
|
||||
}
|
||||
|
||||
(** Elements that can be compared *)
|
||||
let create keys =
|
||||
let t = H.create 5 in
|
||||
(* add k -> zero for each key k *)
|
||||
List.iter (fun key -> H.replace t key (mk_node key)) keys;
|
||||
t
|
||||
|
||||
let mem t key = H.mem t key
|
||||
|
||||
(** Find representative value for this key. *)
|
||||
let rec find_root t key =
|
||||
let node = H.find t key in
|
||||
(* if key is its own representative, done; otherwise recurse toward key's root *)
|
||||
if P.equal key node.n_repr
|
||||
then node
|
||||
else begin
|
||||
(* path compression *)
|
||||
let node' = find_root t node.n_repr in
|
||||
node.n_repr <- node'.n_repr;
|
||||
node'
|
||||
end
|
||||
|
||||
let find t key = (find_root t key).n_repr
|
||||
|
||||
(** Get value of the root for this key. *)
|
||||
let find_value t key = (find_root t key).n_value
|
||||
|
||||
(** Merge two representatives *)
|
||||
let union t k1 k2 =
|
||||
let n1, n2 = find_root t k1, find_root t k2 in
|
||||
if not (P.equal n1.n_repr n2.n_repr)
|
||||
then begin
|
||||
(* k2 points to k1, and k1 points to the new value *)
|
||||
n1.n_value <- P.merge n1.n_value n2.n_value;
|
||||
n2.n_repr <- n1.n_repr;
|
||||
end
|
||||
|
||||
(** Add the given value to the key (monoid) *)
|
||||
let add t key value =
|
||||
try
|
||||
let node = find_root t key in
|
||||
node.n_value <- P.merge node.n_value value
|
||||
with Not_found ->
|
||||
let node = mk_node key in
|
||||
node.n_value <- value;
|
||||
H.add t key node
|
||||
|
||||
(** Iterate on representative and their value *)
|
||||
let iter t f =
|
||||
H.iter
|
||||
(fun key node -> if P.equal key node.n_repr then f key node.n_value)
|
||||
t
|
||||
end
|
||||
85
unionFind.mli
Normal file
85
unionFind.mli
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
(*
|
||||
Copyright (c) 2013, Simon Cruanes
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer. Redistributions in binary
|
||||
form must reproduce the above copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other materials provided with
|
||||
the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*)
|
||||
|
||||
(** {1 Imperative Union-Find structure} *)
|
||||
|
||||
(** This structure operates on arbitrary objects as long as they are
|
||||
hashable. It maps keys to values (values belong to a monoid,
|
||||
if they are not needed, unit makes for a simple implementation)
|
||||
and each equivalence class' representative maps to
|
||||
the monoid merge of all the class' elements values.
|
||||
One also can iterate on the representative elements. *)
|
||||
|
||||
(** We need to be able to hash and compare keys, and values need to form
|
||||
a monoid *)
|
||||
module type PAIR = sig
|
||||
type key
|
||||
type value
|
||||
|
||||
val hash : key -> int
|
||||
val equal : key -> key -> bool
|
||||
|
||||
val merge : value -> value -> value (** Should be associative commutative *)
|
||||
val zero : value (** Neutral element of {!merge} *)
|
||||
end
|
||||
|
||||
(** Build a union-find module from a key/value specification *)
|
||||
module Make(P : PAIR) : sig
|
||||
type key = P.key
|
||||
(** Elements that can be compared *)
|
||||
|
||||
type value = P.value
|
||||
(** Values associated with elements *)
|
||||
|
||||
type t
|
||||
(** The union-find imperative structure itself *)
|
||||
|
||||
val create : key list -> t
|
||||
(** Create a union-find for the given elements. Elements are mapped
|
||||
to zero by default. *)
|
||||
|
||||
val mem : t -> key -> bool
|
||||
(** Does the key belong to the UF? *)
|
||||
|
||||
val find : t -> key -> key
|
||||
(** Finds the representative of this key's equivalence class.
|
||||
@raise Not_found if the key does not belong to the UF *)
|
||||
|
||||
val find_value : t -> key -> value
|
||||
(** Find value for the given element. The value is the monoid
|
||||
merge of all values associated to [key]'s equivalence class.
|
||||
@raise Not_found if [mem uf key] is false. *)
|
||||
|
||||
val union : t -> key -> key -> unit
|
||||
(** Merge two elements (and their equivalence classes) *)
|
||||
|
||||
val add : t -> key -> value -> unit
|
||||
(** Add the given value to the key's class (monoid). It modifies the value
|
||||
by merging it with [value]. If the key does not belong
|
||||
to the union-find, it is added. *)
|
||||
|
||||
val iter : t -> (key -> value -> unit) -> unit
|
||||
(** Iterate on representative and their value *)
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue