87 lines
3.5 KiB
OCaml
87 lines
3.5 KiB
OCaml
|
|
(** Functions for performing binary searches over ordered sequences given
|
||
|
|
[length] and [get] functions.
|
||
|
|
|
||
|
|
These functions can be specialized and added to a data structure using the functors
|
||
|
|
supplied in {{!Base.Binary_searchable}[Binary_searchable]} and described in
|
||
|
|
{{!Base.Binary_searchable_intf}[Binary_searchable_intf]}.
|
||
|
|
|
||
|
|
{2:examples Examples}
|
||
|
|
|
||
|
|
Below we assume that the functions [get], [length] and [compare] are in scope:
|
||
|
|
|
||
|
|
{[
|
||
|
|
(* Find the index of an element [e] in [t] *)
|
||
|
|
binary_search t ~get ~length ~compare `First_equal_to e;
|
||
|
|
|
||
|
|
(* Find the index where an element [e] should be inserted *)
|
||
|
|
binary_search t ~get ~length ~compare `First_greater_than_or_equal_to e;
|
||
|
|
|
||
|
|
(* Find the index in [t] where all elements to the left are less than [e] *)
|
||
|
|
binary_search_segmented t ~get ~length ~segment_of:(fun e' ->
|
||
|
|
if compare e' e <= 0 then `Left else `Right) `First_on_right
|
||
|
|
]} *)
|
||
|
|
|
||
|
|
open! Import
|
||
|
|
|
||
|
|
(** [binary_search ?pos ?len t ~length ~get ~compare which elt] takes [t] that is sorted
|
||
|
|
in increasing order according to [compare], where [compare] and [elt] divide [t] into
|
||
|
|
three (possibly empty) segments:
|
||
|
|
|
||
|
|
{v
|
||
|
|
| < elt | = elt | > elt |
|
||
|
|
v}
|
||
|
|
|
||
|
|
[binary_search] returns the index in [t] of an element on the boundary of segments
|
||
|
|
as specified by [which]. See the diagram below next to the [which] variants.
|
||
|
|
|
||
|
|
By default, [binary_search] searches the entire [t]. One can supply [?pos] or
|
||
|
|
[?len] to search a slice of [t].
|
||
|
|
|
||
|
|
[binary_search] does not check that [compare] orders [t], and behavior is
|
||
|
|
unspecified if [compare] doesn't order [t]. Behavior is also unspecified if
|
||
|
|
[compare] mutates [t]. *)
|
||
|
|
val binary_search
|
||
|
|
: ?pos:int
|
||
|
|
-> ?len:int
|
||
|
|
-> 't
|
||
|
|
-> length:('t -> int)
|
||
|
|
-> get:('t -> int -> 'elt)
|
||
|
|
-> compare:('elt -> 'key -> int)
|
||
|
|
-> [ `Last_strictly_less_than (** {v | < elt X | v} *)
|
||
|
|
| `Last_less_than_or_equal_to (** {v | <= elt X | v} *)
|
||
|
|
| `Last_equal_to (** {v | = elt X | v} *)
|
||
|
|
| `First_equal_to (** {v | X = elt | v} *)
|
||
|
|
| `First_greater_than_or_equal_to (** {v | X >= elt | v} *)
|
||
|
|
| `First_strictly_greater_than (** {v | X > elt | v} *)
|
||
|
|
]
|
||
|
|
-> 'key
|
||
|
|
-> int option
|
||
|
|
|
||
|
|
(** [binary_search_segmented ?pos ?len t ~length ~get ~segment_of which] takes a
|
||
|
|
[segment_of] function that divides [t] into two (possibly empty) segments:
|
||
|
|
|
||
|
|
{v
|
||
|
|
| segment_of elt = `Left | segment_of elt = `Right |
|
||
|
|
v}
|
||
|
|
|
||
|
|
[binary_search_segmented] returns the index of the element on the boundary of the
|
||
|
|
segments as specified by [which]: [`Last_on_left] yields the index of the last
|
||
|
|
element of the left segment, while [`First_on_right] yields the index of the first
|
||
|
|
element of the right segment. It returns [None] if the segment is empty.
|
||
|
|
|
||
|
|
By default, [binary_search] searches the entire [t]. One can supply [?pos] or
|
||
|
|
[?len] to search a slice of [t].
|
||
|
|
|
||
|
|
[binary_search_segmented] does not check that [segment_of] segments [t] as in the
|
||
|
|
diagram, and behavior is unspecified if [segment_of] doesn't segment [t]. Behavior
|
||
|
|
is also unspecified if [segment_of] mutates [t]. *)
|
||
|
|
val binary_search_segmented
|
||
|
|
: ?pos:int
|
||
|
|
-> ?len:int
|
||
|
|
-> 't
|
||
|
|
-> length:('t -> int)
|
||
|
|
-> get:('t -> int -> 'elt)
|
||
|
|
-> segment_of:('elt -> [ `Left | `Right ])
|
||
|
|
-> [ `Last_on_left | `First_on_right ]
|
||
|
|
-> int option
|