Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file splay_tree0_intf.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194openCore(** Splay trees are binary search trees that move recently accessed nodes closer to the
root for easier access. They have amortized O(log n)-time access for a large enough
sequence of primitive operations.
As a heuristic, a splay tree may outperform other trees such as red-black trees when
recently accessed items are more likely to be accessed in the near future.
The amortized complexity analysis only applies if [t] is used as a linear type, i.e.
each [t] returned by access operations is used for the next operation, instead of
being discarded (similar to Fqueue). If, instead, it is used as a persistent data
structure, most primitive operations have O(n) complexity.
*)moduletypeKey=sigtypet[@@derivingsexp,compare]endmoduletypeData=sigtypet[@@derivingsexp]endmoduletypeReduction_operation=sigtypekeytypedatatypeaccumvalidentity:accumvalsingleton:key:key->data:data->accum(** [combine] is required to be associative and have [identity] as its identity.
In other words, they must form a monoid. *)valcombine:accum->accum->accumendtype('k,'d,'a)reduction_operation=(moduleReduction_operationwithtypekey='kandtypedata='dandtypeaccum='a)moduletypeS=sigtypet[@@derivingsexp]typekey[@@derivingsexp]typedata[@@derivingsexp]typeaccumvalempty:tvalof_alist:(key*data)list->tOr_error.tvalof_alist_exn:(key*data)list->tvalto_alist:t->(key*data)listvalis_empty:t->boolvallength:t->intvalaccum:t->accumvalkeys:t->keylistvaldata:t->datalistvalmem:t->key->boolvalfind:t->key->dataoptionvalset:t->key:key->data:data->tvalremove:t->key->tvalremove_min:t->(key*data*t)optionvalremove_max:t->(key*data*t)optionvalremove_after:t->key->(key*data*t)optionvalremove_before:t->key->(key*data*t)optionvalmap:t->f:(data->data)->tvalmap_range:t->min_key:key->max_key:key->f:((key*data)list->(key*data)list)->tvalnth:t->int->(key*data)option(** [rank t key] is the number of nodes before where [key] would be inserted. In other
words, the length of the left subtree after a [split t key]. *)valrank:t->key->int(** [search] implements bisection search over [t] based on the [accum] values
of its prefixes.
Let's consider a [t] consisting of four elements [a; b; c; d] (see diagram below)
(we'll refer to all of key, data, and accum of [a] as just [a]; we'll also assume
[R.combine = (+)]).
Then there are five possible positions to evaluate [f] at (numbered 0..4 below):
+
| position: 0 1 2 3 4
| -------------------------
| element: | a | b | c | d |
| -------------------------
| left: 0 a a+b a+b+c a+b+c+d
| right: a+b+c+d b+c+d c+d d 0
| f ~left ~right: R R R L L
+
The function [f ~left ~right] will be called for a particular position and it takes
the sum of the elements to the left and to the right of this position.
This means [left + right] will be equal to [accum t].
The return value of [f] must indicate the direction where the desired element is.
In the diagram above [f ~left:(a+b) ~right:(c+d)] returns [`Right],
whereas [f ~left:(a+b+c) ~right:d] returns [`Left], which makes [c] the desired
element.
Therefore, [search] will return [c]. If [f] returns the same value at all positions,
[search] returns [None].
For it to make sense, [f] must be monotonic: calling [f] on every possible position
from left to right should produce a prefix of [`Right] values followed by a
suffix of [`Left] values.
Example:
If the values are positive integers and reduction operation is sum, then you can
find the last node where the prefix sum before it is at most [x] with the
following [f]:
{[
let f ~left ~right:_ = if x < left then `Left else `Right
]}
*)valsearch:t->f:(left:accum->right:accum->[`Right|`Left])->(key*data)optionmodulePartition:sigtypenonrect={(* [lt] = values less than the [min_key] of the partition *)lt:t;(* [mid] = values between [min_key] and [max_key] *)mid:t;(* [gt] = values greater than the [max_key] of the partition *)gt:t}endvalpartition:?min_key:key->?max_key:key->t->Partition.t(** [subrange t ?min_key ?max_key] is equivalent to the [mid] in [partition] *)valsubrange:?min_key:key->?max_key:key->t->tvalmerge:t->t->f:(key:key->[`Leftofdata|`Rightofdata|`Bothofdata*data]->dataoption)->tvalsplit:t->key->t*dataoption*t(** [join t1 t2] directly concatenates the sequences described by [t1] and [t2]. This
should be used to rejoin trees obtained by a split operation, though it can be used
for other things.
This operation can fail if the concatenation of the two sequences is invalid; i.e.
the keys are not in order. This happens when the maximum key of [t1] is at or above
the minimum key of [t2].
Currently the cost of [join] is not fully amortized, so it should be considered
worst-case linear time.
*)valjoin:t->t->tOr_error.tvaljoin_exn:t->t->tendmoduletypeSplay_tree=sigmoduletypeKey=KeymoduletypeData=DatamoduletypeReduction_operation=Reduction_operationtypenonrec('k,'d,'a)reduction_operation=('k,'d,'a)reduction_operationmoduletypeS=SmoduleMake_with_reduction(Key:Key)(Data:Data)(R:Reduction_operationwithtypekey=Key.tandtypedata=Data.t):Swithtypekey=Key.tandtypedata=Data.tandtypeaccum=R.accummoduleMake_without_reduction(Key:Key)(Data:Data):Swithtypekey=Key.tandtypedata=Data.tandtypeaccum=unitmoduleReduction_operations:sigvalreduce2:('k,'d,'a)reduction_operation->('k,'d,'b)reduction_operation->('k,'d,'a*'b)reduction_operationendend