123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111type(+'a,+'b)t=|Leaf|Nodeofint*('a,'b)t*'a*'b*('a,'b)tletsize=function|Node(s,_,_,_,_)->s|Leaf->0(** {1 Balance criteria}
Functions are not symmetric.
The first argument should always be of the same power of two or smaller
(guaranteed by construction). *)(** [smaller_ell smin smax] iff
- [smin] is less than [smax]
- [smin] and [smax] differs by less than two magnitude orders, i.e
msbs(smin) >= msbs(smax) - 1
where msbs is the index of the most significant bit set *)letsmaller_ellsminsmax=(smin<smax)&&((sminlandsmax)lsl1<smax)(** [disbalanced smin smax] check if two sub-trees of size [smin] and [smax],
are disbalanced. That is, msbs(smin) < msbs(smax) - 1 *)letdisbalancedsminsmax=smaller_ellsmin(smaxlsr1)(** {1 Smart but not too much constructors} *)(** Construct node and check balance
let node_ l x0 x1 r =
let sl = size l and sr = size r in
if sl < sr then
assert (not (disbalanced sl sr))
else
assert (not (disbalanced sr sl));
Node (sl + 1 + sr, l, x0, x1, r)
*)(** Construct Node *)letnode_lx0x1r=Node(sizel+1+sizer,l,x0,x1,r)(** Rotations *)letrot_leftlx0x1rk=matchrwith|Node(_,rl,y0,y1,rr)->k(klx0x1rl)y0y1rr|_->assertfalseletrot_rightly0y1rk=matchlwith|Node(_,ll,x0,x1,lr)->kllx0x1(klry0y1r)|_->assertfalse(** Balancing *)letinc_leftlx0x1rk=letr=matchrwith|Node(_,rl,y0,y1,rr)whensmaller_ell(sizerr)(sizerl)->rot_rightrly0y1rrk|_->rinrot_leftlx0x1rkletinc_rightly0y1rk=letl=matchlwith|Node(_,ll,x0,x1,lr)whensmaller_ell(sizell)(sizelr)->rot_leftllx0x1lrk|_->linrot_rightly0y1rk(** Balance trees leaning to the right *)letrecnode_leftlx0x1r=ifdisbalanced(sizel)(sizer)theninc_leftlx0x1rnode_leftelsenode_lx0x1r(** Balance trees leaning to the left *)letrecnode_rightly0y1r=ifdisbalanced(sizer)(sizel)theninc_rightly0y1rnode_rightelsenode_ly0y1r(** Public interface *)letleaf=Leafletnodelx0x1r=matchl,rwith|Leaf,Leaf->node_leafx0x1leaf|l,rwhensizel<sizer->node_leftlx0x1r|l,r->node_rightlx0x1rletrecjoinlr=matchl,rwith|Leaf,t|t,Leaf->t|Node(sl,ll,x0,x1,lr),Node(sr,rl,y0,y1,rr)->ifsl<=srthennode(joinlrl)y0y1rrelsenodellx0x1(joinlrr)letrecrankn=function|Leaf->raiseNot_found|Node(_,l,x0,x1,r)->letsl=sizelinifn=slthenx0,x1elseifn<slthenranknlelserank(n-1-sl)r