123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578(* This file is free software, part of containers. See file "license" for more details. *)(** {1 Leftist Heaps} *)type'aiter=('a->unit)->unittype'agen=unit->'aoptiontype'aprinter=Format.formatter->'a->unittype'aktree=unit->[`Nil|`Nodeof'a*'aktreelist]let[@inline]_iter_mapfxsk=xs(funx->k(fx))letrec_gen_iterkg=matchg()with|None->()|Somex->kx;_gen_iterkgmoduletypePARTIAL_ORD=sigtypetvalleq:t->t->bool(** [leq x y] shall return [true] iff [x] is lower or equal to [y]. *)endmoduletypeTOTAL_ORD=sigtypetvalcompare:t->t->int(** [compare a b] shall return
a negative value if [a] is smaller than [b],
[0] if [a] and [b] are equal or
a positive value if [a] is greater than [b] *)endmoduletypeS=sigtypeelttypetexceptionEmpty(** {2 Basing heap operations} *)valempty:t(** Empty heap. *)valis_empty:t->bool(** Is the heap empty? *)valmerge:t->t->t(** [merge h1 h2] merges the two heaps [h1] and [h2].
If one heap is empty, the result is physically equal to the other heap.
Complexity: [O(log (m+n))] where [m] and [n] are the number of elements in each heap.
*)valinsert:elt->t->t(** [insert x h] inserts an element [x] into the heap [h].
Complexity: [O(log n)] where [n] is the number of elements in [h].
*)valadd:t->elt->t(** [add h x] is [insert x h]. *)valfind_min:t->eltoption(** [find_min h] returns the minimal element of [h],
or [None] if [h] is empty.
Complexity: [O(1)].
*)valfind_min_exn:t->elt(** [find_min_exn h] is akin to {!find_min},
but it raises {!Empty} when the heap is empty.
@raise Empty if the heap is empty. *)valtake:t->(t*elt)option(** [take h] returns the minimum element of [h]
and the new heap without this element,
or [None] if [h] is empty.
Complexity: [O(log n)].
*)valtake_exn:t->t*elt(** [take_exn h] is akin to {!take},
but it raises {!Empty} when the heap is empty.
@raise Empty if the heap is empty. *)valsize:t->int(** [size h] is the number of elements in the heap [h].
Complexity: [O(n)].
*)(** {2 Deleting elements} *)valdelete_one:(elt->elt->bool)->elt->t->t(** [delete_one eq x h] deletes an occurrence of the value [x] from the heap
[h],
if there is some.
If [h] does not contain [x], then [h] itself is returned.
Elements are identified by the equality function [eq].
Complexity: [O(n)].
@since 2.0 *)valdelete_all:(elt->elt->bool)->elt->t->t(** [delete_all eq x h] deletes all occurrences of the value [x] from the heap [h].
If [h] does not contain [x], then [h] itself is returned.
Elements are identified by the equality function [eq].
This function is more efficient than {!filter}
because it avoids considering elements greater than [x].
Complexity: [O(n)].
@since 2.0 *)valfilter:(elt->bool)->t->t(** [filter p h] filters the elements of [h],
only retaining those that satisfy the predicate [p].
If no element in [h] satisfies [p], then [h] itself is returned.
Complexity: [O(n)].
*)(** {2 Iterating on elements} *)valiter:(elt->unit)->t->unit(** [iter f h] invokes [f] on every element of the heap [h]. *)valfold:('a->elt->'a)->'a->t->'a(** [fold f acc h] folds on all elements of [h]. *)(** {2 Adding many elements at once} *)valadd_list:t->eltlist->t(** [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.
Elements need not be given in any particular order.
This function is more efficient than repeated insertions.
Complexity: [O(log m + n)]
where [m] and [n] are the number of elements in [h] and [l], respectively.
@since 0.16 *)valadd_iter:t->eltiter->t(** [add_iter h iter] is akin to {!add_list},
but taking an [iter] of elements as input.
@since 2.8 *)valadd_seq:t->eltSeq.t->t(** [add_seq h seq] is akin to {!add_list},
but taking a [Seq.t] of elements as input.
Renamed from [add_std_seq] since 3.0.
@since 3.0 *)valadd_gen:t->eltgen->t(** [add_gen h gen] is akin to {!add_list},
but taking a [gen] of elements as input.
@since 0.16 *)valadd_iter_almost_sorted:t->eltiter->t(** [add_iter_almost_sorted h iter] is equivalent to
[merge h (of_iter_almost_sorted iter)].
See {!of_iter_almost_sorted}.
Complexity: [O(log m + n)].
@since 3.14
*)(** {2 Conversions} *)valof_list:eltlist->t(** [of_list l] builds a heap from the list of elements [l].
Elements need not be given in any particular order.
This function is more efficient than repeated insertions.
It is equivalent to [add_list empty l].
Complexity: [O(n)].
*)valof_iter:eltiter->t(** [of_iter iter] is akin to {!of_list},
but taking an [iter] of elements as input.
@since 2.8 *)valof_seq:eltSeq.t->t(** [of_seq seq] is akin to {!of_list},
but taking a [Seq.t] of elements as input.
Renamed from [of_std_seq] since 3.0.
@since 3.0 *)valof_gen:eltgen->t(** [of_gen gen] is akin to {!of_list},
but taking a [gen] of elements as input. *)valof_iter_almost_sorted:eltiter->t(** [of_iter iter] builds a heap from the {!type:iter} sequence of elements.
Elements need not be given in any particular order.
However, the heap takes advantage of partial sorting found in the input:
the closer the input sequence is to being sorted,
the more efficient it is to convert the heap to a sorted sequence.
This enables heap-sorting that is faster than [O(n log n)]
when the input is almost sorted.
In the best case, when only a constant number of elements are misplaced,
then successive {!take} run in [O(1)],
and {!to_list_sorted} runs in [O(n)].
Complexity: [O(n)].
*)valto_list:t->eltlist(** [to_list h] returns a list of the elements of the heap [h],
in no particular order.
Complexity: [O(n)].
*)valto_iter:t->eltiter(** [to_iter h] is akin to {!to_list}, but returning an [iter] of elements.
@since 2.8 *)valto_seq:t->eltSeq.t(** [to_seq h] is akin to {!to_list}, but returning a [Seq.t] of elements.
Renamed from [to_std_seq] since 3.0.
@since 3.0 *)valto_gen:t->eltgen(** [to_gen h] is akin to {!to_list}, but returning a [gen] of elements. *)valto_list_sorted:t->eltlist(** [to_list_sorted h] returns the list of elements of the heap [h]
in increasing order.
Complexity: [O(n log n)].
@since 1.1 *)valto_iter_sorted:t->eltiter(** [to_iter_sorted h] is akin to {!to_list_sorted},
but returning an [iter] of elements.
@since 2.8 *)valto_seq_sorted:t->eltSeq.t(** [to_seq_sorted h] is akin to {!to_list_sorted},
but returning a [Seq.t] of elements.
Renamed from [to_std_seq_sorted] since 3.0.
@since 3.0 *)valto_tree:t->eltktree(** [to_tree h] returns a [ktree] of the elements of the heap [h].
The layout is not specified.
Complexity: [O(n)].
*)(** {2 Pretty-printing} *)valto_string:?sep:string->(elt->string)->t->string(** Print the heap in a string
@since 2.7 *)valpp:?pp_start:unitprinter->?pp_stop:unitprinter->?pp_sep:unitprinter->eltprinter->tprinter(** Printer.
Renamed from {!print} since 2.0
@since 0.16 *)endmoduleMake(E:PARTIAL_ORD):Swithtypeelt=E.t=structtypeelt=E.ttypet=|E|Nofint*elt*t*tletempty=Eletis_empty=function|E->true|N_->falseexceptionEmptyletsingletonx=N(1,x,E,E)(* Rank of the tree *)let_rank=function|E->0|N(r,_,_,_)->r(* Make a balanced node labelled with [x], and subtrees [a] and [b].
We ensure that the right child's rank is ≤ to the rank of the
left child (leftist property). The rank of the resulting node
is the length of the rightmost path. *)let_make_nodexab=if_ranka>=_rankbthenN(_rankb+1,x,a,b)elseN(_ranka+1,x,b,a)letrecmerget1t2=matcht1,t2with|t,E->t|E,t->t|N(_,x,a1,b1),N(_,y,a2,b2)->ifE.leqxythen_make_nodexa1(mergeb1t2)else_make_nodeya2(merget1b2)letinsertxh=merge(singletonx)hletaddhx=insertxhletfind_min_exn=function|E->raiseEmpty|N(_,x,_,_)->xletfind_min=function|E->None|N(_,x,_,_)->Somexlettake=function|E->None|N(_,x,l,r)->Some(mergelr,x)lettake_exn=function|E->raiseEmpty|N(_,x,l,r)->mergelr,xletreciterfh=matchhwith|E->()|N(_,x,l,r)->fx;iterfl;iterfrletrecfoldfacch=matchhwith|E->acc|N(_,x,a,b)->letacc=faccxinletacc=foldfaccainfoldfaccbletrecsize=function|E->0|N(_,_,l,r)->1+sizel+sizer(** {2 Conversions from sequences} *)(* Merge an [iter] of k heaps into one.
Instead of folding [merge] in one pass (which would run in time O(k log N)
where k is the number of heaps and N is the total number of elements), it
is more efficient to merge heaps pairwise until only one remains; see e.g.
Robert Tarjan, "Data Structures and Network Algorithms",
Chapter 3.3 "Leftist heaps", 1983.
or:
Chris Okasaki, "Purely Functional Data Structures",
Chapter 3.2 "Leftist heaps", Exercise 3.3, 1998
This is independent of the representation of heaps, and, as long as merging
is in time O(log n), this runs in time O(k + k*log(N/k)). Notice that this
is a O(k + N) (if k is small wrt. N, this last upper bound is very loose).
The code below uses additional space of only O(log(k)) at any moment;
it avoids storing an intermediate list of length O(k).
When at most one of the input heaps is non-empty, the result is physically
equal to it. *)let_merge_heap_iter(hs:titer):t=letreccons_and_mergeh0hsweights=matchhswith|h1::hs'whenweightsland1=0->cons_and_merge(mergeh0h1)hs'(weightslsr1)|_->h0::hsin(* the i-th heap in this list is a merger of 2^{w_i} input heaps, each
having gone through w_i merge operations, where the "weights" 2^{w_i} are
strictly increasing wrt. i: *)letmergers=ref[]in(* The w_i are the 1-bits in the binary writing of [count], the number of
input heaps merged so far; adding a heap to the mergers works like binary
incrementation: *)letcount=ref0inhs(funh->incrcount;mergers:=cons_and_mergeh!mergers!count);List.fold_leftmergeE!mergers(* To build a heap with n given values, instead of repeated insertions,
it is more efficient to do pairwise merging, running in time O(n). *)letof_iterxs=xs|>_iter_mapsingleton|>_merge_heap_iterletof_listxs=of_iter(funk->List.iterkxs)letof_seqxs=of_iter(funk->Seq.iterkxs)letof_genxs=of_iter(funk->_gen_iterkxs)(* When input values are sorted in reverse order, then repeated insertions in
a leftist heap run in time O(n) and build a list-like heap where elements
are totally sorted, which makes a subsequent conversion to sorted sequence
run in O(n). *)let_of_list_rev_sorted(xs:eltlist):t=List.fold_left(funhx->N(1,x,h,E))Exs(* We use this to convert an arbitrary input sequence to a heap in time O(n),
while achieving an efficient heap structure in the common situation when
the input is almost sorted. This improves heap-sorting, for instance. *)letof_iter_almost_sortedxs=letsorted_chunk=ref[]inletiter_sorted_heapsk=xs(funx->match!sorted_chunkwith|y::_asyswhennot(E.leqyx)->k(_of_list_rev_sortedys);sorted_chunk:=[x]|ys->sorted_chunk:=x::ys);k(_of_list_rev_sorted!sorted_chunk)in_merge_heap_iteriter_sorted_heaps(** {2 Adding many elements at once} *)letadd_listhxs=mergeh(of_listxs)letadd_iterhxs=mergeh(of_iterxs)letadd_seqhxs=mergeh(of_seqxs)letadd_genhxs=mergeh(of_genxs)letadd_iter_almost_sortedhxs=mergeh(of_iter_almost_sortedxs)(** {2 Conversions to sequences} *)letto_listh=letrecauxacch=matchhwith|E->acc|N(_,x,l,r)->x::aux(auxaccl)rinaux[]hletto_iterhk=iterkhletto_seqh=(* use an explicit stack [st] *)letrecauxst()=matchstwith|[]->Seq.Nil|E::st'->auxst'()|N(_,x,l,r)::st'->Seq.Cons(x,aux(l::r::st'))inaux[h]letto_genh=letstack=Stack.create()inStack.pushhstack;letrecnext()=ifStack.is_emptystackthenNoneelse(matchStack.popstackwith|E->next()|N(_,x,a,b)->Stack.pushastack;Stack.pushbstack;Somex)innextletto_list_sortedheap=letrecrecurseacch=matchtakehwith|None->List.revacc|Some(h',x)->recurse(x::acc)h'inrecurse[]heapletto_iter_sortedheap=letrecrecursehk=matchtakehwith|None->()|Some(h',x)->kx;recurseh'kinfunk->recurseheapkletrecto_seq_sortedh()=matchtakehwith|None->Seq.Nil|Some(h',x)->Seq.Cons(x,to_seq_sortedh')letrecto_treeh()=matchhwith|E->`Nil|N(_,x,l,r)->`Node(x,[to_treel;to_treer])(** {2 Filtering} *)letrecdelete_oneeqx0=function|N(_,x,l,r)ashwhenE.leqxx0->ifeqx0xthenmergelrelse(letl'=delete_oneeqx0linifCCEqual.physicall'lthen(letr'=delete_oneeqx0rinifCCEqual.physicalr'rthenhelse_make_nodexlr')else_make_nodexl'r)|h->hletdelete_alleqx0h=(* Iterates [k] on sub-heaps of [h] whose merger is equal to [h] minus
the deleted elements [x0]; we do this, instead of merging the subheaps
directly, in order to ensure complexity O(n).
When no element is deleted, the iterator does nothing and the function
returns true; this makes sure that the result shares sub-heaps with the
input as much as possible, and ensures physical equality when no element
is deleted.
In [delete_all], by contrast with [filter], we can avoid considering
elements greater than [x0]. As a consequence, the complexity is more
precisely O(k + k log(n/k)), where k is the number of elements not
greater than [x0]. This is a O(n), but it is also a O(k log n), which is
much smaller than O(n) if k is asymptotically smaller than n.
*)letreciter_subheapseqx0hk=matchhwith|N(_,x,l,r)whenE.leqxx0->letkeep_x=not(eqx0x)inletkeep_l=iter_subheapseqx0lkinletkeep_r=iter_subheapseqx0rkinifkeep_x&&keep_l&&keep_rthentrueelse(ifkeep_xthenk(singletonx);ifkeep_lthenkl;ifkeep_rthenkr;false)|_->truein_merge_heap_iter(funk->ifiter_subheapseqx0hkthenkh)letfilterph=(* similar to [delete_all] *)letreciter_subheapspkh=matchhwith|E->true|N(_,x,l,r)->letkeep_x=pxinletkeep_l=iter_subheapspklinletkeep_r=iter_subheapspkrinifkeep_x&&keep_l&&keep_rthentrueelse(ifkeep_xthenk(singletonx);ifkeep_lthenkl;ifkeep_rthenkr;false)in_merge_heap_iter(funk->ifiter_subheapspkhthenkh)(** {2 Pretty-printing} *)letto_string?(sep=",")elt_to_stringh=to_list_sortedh|>List.mapelt_to_string|>String.concatsepletpp?(pp_start=fun_()->())?(pp_stop=fun_()->())?(pp_sep=funout()->Format.fprintfout",")pp_eltouth=letfirst=reftrueinpp_startout();iter(funx->if!firstthenfirst:=falseelsepp_sepout();pp_eltoutx)h;pp_stopout()endmoduleMake_from_compare(E:TOTAL_ORD)=Make(structtypet=E.tletleqab=E.compareab<=0end)