mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2025-12-06 11:15:31 -05:00
doc/CCHeap: document complexities
Committing to these complexities in documentation is not a constraint for representation of heaps, because they are achieved by every well-known representation (for some of them, in amortized time): https://en.wikipedia.org/wiki/Template:Heap_Running_Times - `find_min`: O(1) - `take`: O(log n) - `insert`: O(log n) - `merge`: O(log(m+n)) (excepted binary heaps which only achieve O(m+n)) - `add_seq`: O(n log(m+n)) (trivially, by repeated insertion) + this can be improved to O(log(m) + n), regardless of the representation of heaps (to be done in a later commit) - `of_seq`: O(n log n) (ditto: can be improved to O(n)) Less trivial: - `filter`, `delete_{one,all}`: + O(n) can be achieved for any reasonable representation of heaps, by using `of_seq` and `to_seq` which, as said, can always be made O(n). + With the current implementation, it is not obvious, but the complexity of `filter` and `delete_all` is Θ(n log n); the complexity of `delete_one` is O(n). Indeed, node rebuilding with `_make_node` is in O(1), merging is in Θ(log n), and every element deletion induces one merge; there are heap instances that achieve the worst case Ω(n log n), for instance: x / \ x y / \ ... y / x / \ h y with n/3 occurrences of x, n/3 occurrences of y, a sub-heap h of n/3 elements, and when y is greater than all elements of h; then, deleting all occurrences of x performs the following computation: merge (merge (merge (merge h y) …) y) y where each `merge` takes time Θ(log n).
This commit is contained in:
parent
8666faf257
commit
793bad1e5b
2 changed files with 60 additions and 22 deletions
|
|
@ -37,37 +37,47 @@ module type S = sig
|
||||||
exception Empty
|
exception Empty
|
||||||
|
|
||||||
val merge : t -> t -> t
|
val merge : t -> t -> t
|
||||||
(** Merge two heaps. *)
|
(** [merge h1 h2] merges the two heaps [h1] and [h2].
|
||||||
|
Complexity: [O(log (m+n))] where [m] and [n] are the number of elements in each heap.
|
||||||
|
*)
|
||||||
|
|
||||||
val insert : elt -> t -> t
|
val insert : elt -> t -> t
|
||||||
(** Insert a value in the heap. *)
|
(** [insert x h] inserts an element [x] into the heap [h].
|
||||||
|
Complexity: [O(log n)] where [n] is the number of elements in [h].
|
||||||
|
*)
|
||||||
|
|
||||||
val add : t -> elt -> t
|
val add : t -> elt -> t
|
||||||
(** Synonym to {!insert}. *)
|
(** [add h x] is [insert x h]. *)
|
||||||
|
|
||||||
val filter : (elt -> bool) -> t -> t
|
val filter : (elt -> bool) -> t -> t
|
||||||
(** Filter values, only retaining the ones that satisfy the predicate.
|
(** [filter p h] filters values, only retaining the ones that satisfy the predicate [p].
|
||||||
Linear time at least. *)
|
Complexity: [O(n log n)].
|
||||||
|
*)
|
||||||
|
|
||||||
val find_min : t -> elt option
|
val find_min : t -> elt option
|
||||||
(** Find minimal element. *)
|
(** [find_min h] find the minimal element of the heap [h].
|
||||||
|
Complexity: [O(1)].
|
||||||
|
*)
|
||||||
|
|
||||||
val find_min_exn : t -> elt
|
val find_min_exn : t -> elt
|
||||||
(** Like {!find_min} but can fail.
|
(** [find_min_exn h] is like {!find_min} but can fail.
|
||||||
@raise Empty if the heap is empty. *)
|
@raise Empty if the heap is empty. *)
|
||||||
|
|
||||||
val take : t -> (t * elt) option
|
val take : t -> (t * elt) option
|
||||||
(** Extract and return the minimum element, and the new heap (without
|
(** [take h] extracts and returns the minimum element, and the new heap (without
|
||||||
this element), or [None] if the heap is empty. *)
|
this element), or [None] if the heap [h] is empty.
|
||||||
|
Complexity: [O(log n)].
|
||||||
|
*)
|
||||||
|
|
||||||
val take_exn : t -> t * elt
|
val take_exn : t -> t * elt
|
||||||
(** Like {!take}, but can fail.
|
(** [take_exn h] is like {!take}, but can fail.
|
||||||
@raise Empty if the heap is empty. *)
|
@raise Empty if the heap is empty. *)
|
||||||
|
|
||||||
val delete_one : (elt -> elt -> bool) -> elt -> t -> t
|
val delete_one : (elt -> elt -> bool) -> elt -> t -> t
|
||||||
(** Delete one occurrence of a value if it exist in the heap.
|
(** Delete one occurrence of a value if it exist in the heap.
|
||||||
[delete_one eq x h], use [eq] to find one [x] in [h] and delete it.
|
[delete_one eq x h], use [eq] to find one [x] in [h] and delete it.
|
||||||
If [h] do not contain [x] then it return [h].
|
If [h] do not contain [x] then it return [h].
|
||||||
|
Complexity: [O(n)].
|
||||||
@since 2.0 *)
|
@since 2.0 *)
|
||||||
|
|
||||||
val delete_all : (elt -> elt -> bool) -> elt -> t -> t
|
val delete_all : (elt -> elt -> bool) -> elt -> t -> t
|
||||||
|
|
@ -76,22 +86,27 @@ module type S = sig
|
||||||
If [h] do not contain [x] then it return [h].
|
If [h] do not contain [x] then it return [h].
|
||||||
The difference with {!filter} is that [delete_all] stops as soon as
|
The difference with {!filter} is that [delete_all] stops as soon as
|
||||||
it enters a subtree whose root is bigger than the element.
|
it enters a subtree whose root is bigger than the element.
|
||||||
|
Complexity: [O(n log n)].
|
||||||
@since 2.0 *)
|
@since 2.0 *)
|
||||||
|
|
||||||
val iter : (elt -> unit) -> t -> unit
|
val iter : (elt -> unit) -> t -> unit
|
||||||
(** Iterate on elements. *)
|
(** [iter f h] iterates over the heap [h] invoking [f] with the current element. *)
|
||||||
|
|
||||||
val fold : ('a -> elt -> 'a) -> 'a -> t -> 'a
|
val fold : ('a -> elt -> 'a) -> 'a -> t -> 'a
|
||||||
(** Fold on all values. *)
|
(** [fold f acc h] folds on all values of [h]. *)
|
||||||
|
|
||||||
val size : t -> int
|
val size : t -> int
|
||||||
(** Number of elements (linear complexity). *)
|
(** [size h] is the number of elements in the heap [h].
|
||||||
|
Complexity: [O(n)].
|
||||||
|
*)
|
||||||
|
|
||||||
(** {2 Adding many elements at once} *)
|
(** {2 Adding many elements at once} *)
|
||||||
|
|
||||||
val add_list : t -> elt list -> t
|
val add_list : t -> elt list -> t
|
||||||
(** [add_list h l] adds the elements of the list [l] into the heap [h].
|
(** [add_list h l] adds the elements of the list [l] into the heap [h].
|
||||||
An element occurring several times will be added that many times to the heap.
|
An element occurring several times will be added that many times to the heap.
|
||||||
|
Complexity: [O(n log (m+n))]
|
||||||
|
where [m] and [n] are the number of elements in [h] and [l], respectively.
|
||||||
@since 0.16 *)
|
@since 0.16 *)
|
||||||
|
|
||||||
val add_iter : t -> elt iter -> t
|
val add_iter : t -> elt iter -> t
|
||||||
|
|
@ -136,6 +151,7 @@ module type S = sig
|
||||||
val to_list : t -> elt list
|
val to_list : t -> elt list
|
||||||
(** [to_list h] returns a list of the elements of the heap [h],
|
(** [to_list h] returns a list of the elements of the heap [h],
|
||||||
in no particular order.
|
in no particular order.
|
||||||
|
Complexity: [O(n)].
|
||||||
*)
|
*)
|
||||||
|
|
||||||
val to_iter : t -> elt iter
|
val to_iter : t -> elt iter
|
||||||
|
|
@ -153,6 +169,7 @@ module type S = sig
|
||||||
val to_list_sorted : t -> elt list
|
val to_list_sorted : t -> elt list
|
||||||
(** [to_list_sorted h] returns the list of elements of the heap [h]
|
(** [to_list_sorted h] returns the list of elements of the heap [h]
|
||||||
in increasing order.
|
in increasing order.
|
||||||
|
Complexity: [O(n log n)].
|
||||||
@since 1.1 *)
|
@since 1.1 *)
|
||||||
|
|
||||||
val to_iter_sorted : t -> elt iter
|
val to_iter_sorted : t -> elt iter
|
||||||
|
|
@ -168,7 +185,9 @@ module type S = sig
|
||||||
|
|
||||||
val to_tree : t -> elt ktree
|
val to_tree : t -> elt ktree
|
||||||
(** [to_tree h] returns a [ktree] of the elements of the heap [h].
|
(** [to_tree h] returns a [ktree] of the elements of the heap [h].
|
||||||
The layout is not specified. *)
|
The layout is not specified.
|
||||||
|
Complexity: [O(n)].
|
||||||
|
*)
|
||||||
|
|
||||||
(** {2 Pretty-printing} *)
|
(** {2 Pretty-printing} *)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,20 +42,27 @@ module type S = sig
|
||||||
exception Empty
|
exception Empty
|
||||||
|
|
||||||
val merge : t -> t -> t
|
val merge : t -> t -> t
|
||||||
(** [merge h1 h2] merges the two heaps [h1] and [h2]. *)
|
(** [merge h1 h2] merges the two heaps [h1] and [h2].
|
||||||
|
Complexity: [O(log (m+n))] where [m] and [n] are the number of elements in each heap.
|
||||||
|
*)
|
||||||
|
|
||||||
val insert : elt -> t -> t
|
val insert : elt -> t -> t
|
||||||
(** [insert x h] inserts an element [x] into the heap [h]. *)
|
(** [insert x h] inserts an element [x] into the heap [h].
|
||||||
|
Complexity: [O(log n)] where [n] is the number of elements in [h].
|
||||||
|
*)
|
||||||
|
|
||||||
val add : t -> elt -> t
|
val add : t -> elt -> t
|
||||||
(** [add h x] inserts an element [x] into the heap [h]. *)
|
(** [add h x] is [insert x h]. *)
|
||||||
|
|
||||||
val filter : (elt -> bool) -> t -> t
|
val filter : (elt -> bool) -> t -> t
|
||||||
(** [filter p h] filters values, only retaining the ones that satisfy the predicate [p].
|
(** [filter p h] filters values, only retaining the ones that satisfy the predicate [p].
|
||||||
Linear time at least. *)
|
Complexity: [O(n log n)].
|
||||||
|
*)
|
||||||
|
|
||||||
val find_min : t -> elt option
|
val find_min : t -> elt option
|
||||||
(** [find_min h] find the minimal element of the heap [h]. *)
|
(** [find_min h] find the minimal element of the heap [h].
|
||||||
|
Complexity: [O(1)].
|
||||||
|
*)
|
||||||
|
|
||||||
val find_min_exn : t -> elt
|
val find_min_exn : t -> elt
|
||||||
(** [find_min_exn h] is like {!find_min} but can fail.
|
(** [find_min_exn h] is like {!find_min} but can fail.
|
||||||
|
|
@ -63,7 +70,9 @@ module type S = sig
|
||||||
|
|
||||||
val take : t -> (t * elt) option
|
val take : t -> (t * elt) option
|
||||||
(** [take h] extracts and returns the minimum element, and the new heap (without
|
(** [take h] extracts and returns the minimum element, and the new heap (without
|
||||||
this element), or [None] if the heap [h] is empty. *)
|
this element), or [None] if the heap [h] is empty.
|
||||||
|
Complexity: [O(log n)].
|
||||||
|
*)
|
||||||
|
|
||||||
val take_exn : t -> t * elt
|
val take_exn : t -> t * elt
|
||||||
(** [take_exn h] is like {!take}, but can fail.
|
(** [take_exn h] is like {!take}, but can fail.
|
||||||
|
|
@ -73,6 +82,7 @@ module type S = sig
|
||||||
(** [delete_one eq x h] uses [eq] to find one occurrence of a value [x]
|
(** [delete_one eq x h] uses [eq] to find one occurrence of a value [x]
|
||||||
if it exist in the heap [h], and delete it.
|
if it exist in the heap [h], and delete it.
|
||||||
If [h] do not contain [x] then it return [h].
|
If [h] do not contain [x] then it return [h].
|
||||||
|
Complexity: [O(n)].
|
||||||
@since 2.0 *)
|
@since 2.0 *)
|
||||||
|
|
||||||
val delete_all : (elt -> elt -> bool) -> elt -> t -> t
|
val delete_all : (elt -> elt -> bool) -> elt -> t -> t
|
||||||
|
|
@ -80,6 +90,7 @@ module type S = sig
|
||||||
If [h] do not contain [x] then it return [h].
|
If [h] do not contain [x] then it return [h].
|
||||||
The difference with {!filter} is that [delete_all] stops as soon as
|
The difference with {!filter} is that [delete_all] stops as soon as
|
||||||
it enters a subtree whose root is bigger than the element.
|
it enters a subtree whose root is bigger than the element.
|
||||||
|
Complexity: [O(n log n)].
|
||||||
@since 2.0 *)
|
@since 2.0 *)
|
||||||
|
|
||||||
val iter : (elt -> unit) -> t -> unit
|
val iter : (elt -> unit) -> t -> unit
|
||||||
|
|
@ -89,13 +100,17 @@ module type S = sig
|
||||||
(** [fold f acc h] folds on all values of [h]. *)
|
(** [fold f acc h] folds on all values of [h]. *)
|
||||||
|
|
||||||
val size : t -> int
|
val size : t -> int
|
||||||
(** [size h] is the number of elements in the heap [h]. Linear complexity. *)
|
(** [size h] is the number of elements in the heap [h].
|
||||||
|
Complexity: [O(n)].
|
||||||
|
*)
|
||||||
|
|
||||||
(** {2 Adding many elements at once} *)
|
(** {2 Adding many elements at once} *)
|
||||||
|
|
||||||
val add_list : t -> elt list -> t
|
val add_list : t -> elt list -> t
|
||||||
(** [add_list h l] adds the elements of the list [l] into the heap [h].
|
(** [add_list h l] adds the elements of the list [l] into the heap [h].
|
||||||
An element occurring several times will be added that many times to the heap.
|
An element occurring several times will be added that many times to the heap.
|
||||||
|
Complexity: [O(n log (m+n))]
|
||||||
|
where [m] and [n] are the number of elements in [h] and [l], respectively.
|
||||||
@since 0.16 *)
|
@since 0.16 *)
|
||||||
|
|
||||||
val add_iter : t -> elt iter -> t
|
val add_iter : t -> elt iter -> t
|
||||||
|
|
@ -140,6 +155,7 @@ module type S = sig
|
||||||
val to_list : t -> elt list
|
val to_list : t -> elt list
|
||||||
(** [to_list h] returns a list of the elements of the heap [h],
|
(** [to_list h] returns a list of the elements of the heap [h],
|
||||||
in no particular order.
|
in no particular order.
|
||||||
|
Complexity: [O(n)].
|
||||||
*)
|
*)
|
||||||
|
|
||||||
val to_iter : t -> elt iter
|
val to_iter : t -> elt iter
|
||||||
|
|
@ -157,6 +173,7 @@ module type S = sig
|
||||||
val to_list_sorted : t -> elt list
|
val to_list_sorted : t -> elt list
|
||||||
(** [to_list_sorted h] returns the list of elements of the heap [h]
|
(** [to_list_sorted h] returns the list of elements of the heap [h]
|
||||||
in increasing order.
|
in increasing order.
|
||||||
|
Complexity: [O(n log n)].
|
||||||
@since 1.1 *)
|
@since 1.1 *)
|
||||||
|
|
||||||
val to_iter_sorted : t -> elt iter
|
val to_iter_sorted : t -> elt iter
|
||||||
|
|
@ -172,7 +189,9 @@ module type S = sig
|
||||||
|
|
||||||
val to_tree : t -> elt ktree
|
val to_tree : t -> elt ktree
|
||||||
(** [to_tree h] returns a [ktree] of the elements of the heap [h].
|
(** [to_tree h] returns a [ktree] of the elements of the heap [h].
|
||||||
The layout is not specified. *)
|
The layout is not specified.
|
||||||
|
Complexity: [O(n)].
|
||||||
|
*)
|
||||||
|
|
||||||
(** {2 Pretty-printing} *)
|
(** {2 Pretty-printing} *)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue