Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // avl.c
- #include "avl.h"
- #include <stdlib.h>
- #define AVL_MEM_ALLOC(size) malloc(size)
- #define AVL_MEM_FREE(p) free(p)
- enum { avl_max_height=40 };
- // 40--> min 267914295 nodes (3Gb) (MH ~ 1.440*ln2(N)-0.328)
- // S(0)=0
- // S(1)=1
- // S(n)=1+S(n-1)+S(n-2)
- //...
- // S(19)=10945
- // S(24)=121392
- // S(40)=267914295
- // S(41)=433494436
- // S(64)=27777890035287
- // S(86)=1100087778366101930
- // S(193)=25299086886458645685589389182743678652929
- //...
- // 16bit->19, 24bit->24, 32bit->41, 48bit->64, 64bit->86, 128bit->193
- #define AVL_ITEM(n) (void*)( (char*)avl->items + avl->item_size*(n) )
- #define AVL_CMP1(item,n) avl->cmp(avl->cmp_ctx,item ,AVL_ITEM(n))
- #define AVL_CMP2(a,b) avl->cmp(avl->cmp_ctx,AVL_ITEM(a),AVL_ITEM(b))
- #define AVL_LEFT(n) (avl->LR[2*(n)]>>2)
- #define AVL_RIGHT(n) (avl->LR[2*(n)+1])
- #define AVL_FLG(n) (avl->LR[2*(n)]&3)
- #define AVL_SET_LEFT(n,v) (avl->LR[2*(n)]=(avl->LR[2*(n)]&3)|((v)<<2))
- #define AVL_SET_RIGHT(n,v) (avl->LR[2*(n)+1]=(v))
- #define AVL_SET_CHILD(n,dir,v) \
- {if (dir) avl->LR[2*(n)+1]=(v); \
- else avl->LR[2*(n)]=(avl->LR[2*(n)]&3)|((v)<<2);}
- #define AVL_SET_FLG(n,v) (avl->LR[2*(n)]=(avl->LR[2*(n)]&~3)|(v))
- #define AVL_MARK_ERASED(n) (avl->LR[2*(n)]=avl_none)
- #define AVL_SET_NOCHILD(n) \
- {avl->LR[2*(n)]=(avl_none<<2)+1; avl->LR[2*(n)+1]=avl_none;}
- #define AVL_COPY(n,item) {avl->copy(avl->copy_ctx,AVL_ITEM(n),item);}
- #define AVL_COPY_CHILDREN(d,s) \
- {avl->LR[2*(d)]=avl->LR[2*(s)]; avl->LR[2*(d)+1]=avl->LR[2*(s)+1];}
- int avl_clear(avl_t *avl) {
- avl->count=0;
- avl->size=0;
- avl->root=avl_none;
- avl->tail=avl_none;
- }
- int avl_init(avl_t *avl,int limit) {
- avl->LR=(int*)AVL_MEM_ALLOC(limit*2*sizeof(int));
- avl->items=AVL_MEM_ALLOC(limit*avl->item_size);
- avl->limit=limit;
- avl_clear(avl);
- }
- void avl_done(avl_t *avl) {
- AVL_MEM_FREE(avl->items); avl->items=0;
- AVL_MEM_FREE(avl->LR); avl->LR=0;
- avl->limit=0;
- avl_clear(avl);
- }
- static int avl_alloc(avl_t *avl) {
- int r;
- if (avl->count==0) {
- if (avl->limit==0) return avl_none;
- avl->count=1;
- avl->size=1;
- avl->tail=avl_none;
- r=0;
- } else {
- r=avl->tail;
- if (r!=avl_none) {
- avl->tail=AVL_RIGHT(avl->tail);
- } else {
- if (avl->size>=avl->limit) {
- if (avl->ovf) avl->ovf(avl->ovf_ctx,avl);
- if (avl->size>=avl->limit) {
- return avl_none;
- }
- }
- r=avl->size++;
- }
- avl->count++;
- }
- AVL_SET_NOCHILD(r);
- return r;
- }
- static void avl_free(avl_t *avl,int n) {
- AVL_MARK_ERASED(n);
- AVL_SET_RIGHT(n,avl->tail);
- avl->tail=n;
- avl->count--;
- }
- int avl_find(avl_t *avl,void *item) {
- int r=avl->root;
- while(r!=avl_none) {
- int c=AVL_CMP1(item,r); if (c==0) return r;
- if (c<0) r=AVL_LEFT(r); else r=AVL_RIGHT(r);
- }
- return avl_none;
- }
- static int avl_sl(avl_t *avl,int A) {
- int B,b;
- // h+3 h+2
- // | |
- // A:-2 B:0
- // / \ / \
- // B:-1 g:h ==> a:h+1 A:0
- // / \ / \
- // a:h+1 b:h b:h g:h
- B=AVL_LEFT(A); b=AVL_RIGHT(B);
- AVL_SET_LEFT(A,b); AVL_SET_RIGHT(B,A);
- AVL_SET_FLG(B,1); AVL_SET_FLG(A,1);
- return B;
- }
- static int avl_sr(avl_t *avl,int A) {
- int B,b;
- // h+3 h+2
- // | |
- // A:+2 B:0
- // / \ / \
- // a:h B:+1 ==> A:0 g:h+1
- // / \ / \
- // b:h g:h+1 a:h b:h
- B=AVL_RIGHT(A); b=AVL_LEFT(B);
- AVL_SET_RIGHT(A,b); AVL_SET_LEFT(B,A);
- AVL_SET_FLG(B,1); AVL_SET_FLG(A,1);
- return B;
- }
- static int avl_lr(avl_t *avl,int A) {
- int B,C,b,g;
- // h+3 h+2
- // | |
- // A:-2 C:0 x= 0 if C.f=0,-1
- // / \ / \ x=-1 if C.f=+1
- // B:+1 d:h ==> B:x A:y y= 0 if C.f=0,+1
- // / \ / \ / \ y=+1 if C.f=-1
- // a:h C:f a:h b<=h g<=h d:h
- // / \
- // [b g]:h
- B=AVL_LEFT(A); C=AVL_RIGHT(B);
- b=AVL_LEFT(C); g=AVL_RIGHT(C);
- AVL_SET_RIGHT(B,b);
- AVL_SET_LEFT(A,g);
- AVL_SET_LEFT(C,B);
- AVL_SET_RIGHT(C,A);
- AVL_SET_FLG(B,AVL_FLG(C)==2?0:1);
- AVL_SET_FLG(A,AVL_FLG(C)==0?2:1);
- AVL_SET_FLG(C,1);
- return C;
- }
- static int avl_rl(avl_t *avl,int A) {
- int B,C,b,g;
- // h+3 h+2
- // | |
- // A:+2 C:0 x= 0 if C.f=0,-1
- // / \ / \ x=-1 if C.f=+1
- // a:h B:-1 ==> A:x B:y y= 0 if C.f=0,+1
- // / \ / \ / \ y=+1 if C.f=-1
- // C:f d:h a:h b<=h g<=h d:h
- // / \
- // [b g]:h
- B=AVL_RIGHT(A); C=AVL_LEFT(B);
- b=AVL_LEFT(C); g=AVL_RIGHT(C);
- AVL_SET_RIGHT(A,b);
- AVL_SET_LEFT(B,g);
- AVL_SET_LEFT(C,A);
- AVL_SET_RIGHT(C,B);
- AVL_SET_FLG(A,AVL_FLG(C)==2?0:1);
- AVL_SET_FLG(B,AVL_FLG(C)==0?2:1);
- AVL_SET_FLG(C,1);
- return C;
- }
- static int avl_sl0(avl_t *avl,int A) {
- int B,b;
- // h+3 h+3
- // | |
- // A:-2 B:+1
- // / \ / \
- // B:0 g:h ==> a:h+1 A:-1
- // / \ / \
- // a:h+1 b:h+1 b:h+1 g:h
- B=AVL_LEFT(A); b=AVL_RIGHT(B);
- AVL_SET_LEFT(A,b); AVL_SET_RIGHT(B,A);
- AVL_SET_FLG(B,2); AVL_SET_FLG(A,0);
- return B;
- }
- static int avl_sr0(avl_t *avl,int A) {
- int B,b;
- // h+3 h+3
- // | |
- // A:+2 B:-1
- // / \ / \
- // a:h B:0 ==> A:1 g:h+1
- // / \ / \
- // b:h+1 g:h+1 a:h b:h+1
- B=AVL_RIGHT(A); b=AVL_LEFT(B);
- AVL_SET_RIGHT(A,b); AVL_SET_LEFT(B,A);
- AVL_SET_FLG(B,0); AVL_SET_FLG(A,2);
- return B;
- }
- int avl_insert(avl_t *avl,void *item) {
- int flg,pp,tt,t,r;
- int path[avl_max_height];
- if (!item) return avl_none;
- r=avl->root;
- if (r==avl_none) { // trivial case
- r=avl_alloc(avl);
- avl->root=r;
- if (r!=avl_none) AVL_COPY(r,item);
- return r;
- }
- pp=-1;
- // 1. find node
- do {
- int v=r<<1, c=AVL_CMP1(item,r);
- if (c<0) { r=AVL_LEFT(r); } else
- if (c>0) { r=AVL_RIGHT(r); v++; } else return r;
- path[++pp]=v;
- } while(r!=avl_none);
- // 2. create new node
- r=avl_alloc(avl); if (r==avl_none) return r; // overflow. no room
- AVL_COPY(r,item);
- AVL_SET_CHILD(path[pp]>>1,path[pp]&1,r);
- // 3. walk back and rebalance tree
- for(;pp>=0;pp--) {
- t=path[pp]>>1; flg=AVL_FLG(t);
- if (path[pp]&1) { // right
- if (flg==0) { AVL_SET_FLG(t,1); break; }
- if (flg==1) { AVL_SET_FLG(t,2); continue; }
- tt=AVL_RIGHT(t); // Skew=+2
- flg=AVL_FLG(tt);
- if (flg==2) t=avl_sr(avl,t); else if (flg==0) t=avl_rl(avl,t);
- } else { // left
- if (flg==2) { AVL_SET_FLG(t,1); break; }
- if (flg==1) { AVL_SET_FLG(t,0); continue; }
- tt=AVL_LEFT(t); // Skew=-2
- flg=AVL_FLG(tt);
- if (flg==0) t=avl_sl(avl,t); else if (flg==2) t=avl_lr(avl,t);
- }
- if (pp>0) { AVL_SET_CHILD(path[pp-1]>>1,path[pp-1]&1,t); }
- else avl->root=t;
- break;
- }
- return r;
- }
- int avl_remove(avl_t *avl,void *item) { // O(ln(n))
- int mp,pp,r,thd;
- int path[avl_max_height];
- if (!item) return avl_none;
- pp=0; r=avl->root;
- // 1. find node to erase
- for(;r!=avl_none;pp++) {
- int v=r<<1, c=AVL_CMP1(item,r);
- if (c<0) { r=AVL_LEFT(r); } else
- if (c>0) { r=AVL_RIGHT(r); v++; } else
- { path[pp]=v; break; } // find node to erase
- path[pp]=v;
- }
- if (r==avl_none) return r; // no node found
- // 2. look around. check childs
- if (AVL_LEFT(r)==avl_none) { // right child or none
- int rn=AVL_RIGHT(r);
- if (pp>0) { AVL_SET_CHILD(path[pp-1]>>1,path[pp-1]&1,rn); }
- else avl->root=rn;
- } else if (AVL_RIGHT(r)==avl_none) { // only left child
- int ln=AVL_LEFT(r);
- if (pp>0) { AVL_SET_CHILD(path[pp-1]>>1,path[pp-1]&1,ln); }
- else avl->root=ln;
- } else { // we've got both childs
- int w,mn,ri,z=AVL_RIGHT(r);
- mp=pp; path[pp]|=1; path[++pp]=z<<1;
- // find sub tree min node
- for(w=AVL_LEFT(z);w!=avl_none;w=AVL_LEFT(w)) {
- path[pp]&=~1; path[++pp]=w<<1;
- }
- mn=path[pp]>>1; ri=AVL_RIGHT(mn);
- AVL_SET_CHILD(path[pp-1]>>1,path[pp-1]&1,ri);
- if (mp>0) { AVL_SET_CHILD(path[mp-1]>>1,path[mp-1]&1,mn); }
- else avl->root=mn;
- AVL_COPY_CHILDREN(mn,r); path[mp]=(mn<<1)|(path[mp]&1);
- }
- avl_free(avl,r); pp--;
- // 3. walk back and rebalance tree
- for(thd=1;pp>=0;pp--) {
- int t=path[pp]>>1, flg=AVL_FLG(t), tl,tr;
- if (path[pp]&1) { // from right
- if (flg==2) { AVL_SET_FLG(t,1); continue; }
- if (flg==1) { AVL_SET_FLG(t,0); break; }
- tl=AVL_LEFT(t); // skew=-2
- flg=AVL_FLG(tl);
- if (flg==0) t=avl_sl(avl,t); else if (flg==2) t=avl_lr(avl,t);
- else { thd=0; t=avl_sl0(avl,t); }
- } else { // from left
- if (flg==0) { AVL_SET_FLG(t,1); continue; }
- if (flg==1) { AVL_SET_FLG(t,2); break; }
- tr=AVL_RIGHT(t); // skew=+2
- flg=AVL_FLG(tr);
- if (flg==2) t=avl_sr(avl,t); else if (flg==0) t=avl_rl(avl,t);
- else { thd=0; t=avl_sr0(avl,t); }
- }
- if (pp>0) { AVL_SET_CHILD(path[pp-1]>>1,path[pp-1]&1,t); }
- else avl->root=t;
- if (!thd) break;
- }
- return r;
- }
- int avl_get(avl_t *avl,int n,void *item) {
- if (n<0 || n>=avl->limit) return avl_none; // out of bounds
- if (AVL_FLG(n)==3) return avl_none; // erased item
- if (item) avl->copy(avl->copy_ctx,item,AVL_ITEM(n));
- return n;
- }
- int avl_min(avl_t *avl,void *item) {
- int t,r=avl->root; if (r==avl_none) return avl_none;
- for(;;r=t) {
- t=AVL_LEFT(r);
- if (t==avl_none) break;
- }
- return avl_get(avl,r,item);
- }
- int avl_max(avl_t *avl,void *item) {
- int t,r=avl->root; if (r==avl_none) return avl_none;
- for(;;r=t) {
- t=AVL_RIGHT(r);
- if (t==avl_none) break;
- }
- return avl_get(avl,r,item);
- }
- int avl_next(avl_t *avl,void *item) {
- int pp,r,rr,c;
- int path[avl_max_height];
- r=avl->root; if (r==avl_none || !item) return r; // trivial case
- pp=-1;
- // 1. find node
- do {
- int v=r<<1; c=AVL_CMP1(item,r);
- if (c<0) { r=AVL_LEFT(r); } else
- if (c>0) { r=AVL_RIGHT(r); v++; }
- path[++pp]=v;
- if (c==0) break;
- } while(r!=avl_none);
- if (c>0) r=path[pp]>>1;
- if (r!=avl_none) { // c=0 found item
- r=AVL_RIGHT(r);
- if (r==avl_none) {
- while(pp>0 && path[pp-1]&1) --pp;
- rr=pp>0 ? path[pp-1]>>1 : avl_none;
- } else {
- do { rr=r; r=AVL_LEFT(r); } while(r!=avl_none);
- }
- } else { // no iten found & c<0
- rr=path[pp]>>1;
- }
- if (rr!=avl_none) avl->copy(avl->copy_ctx,item,AVL_ITEM(rr));
- return rr;
- }
- int avl_prev(avl_t *avl,void *item) {
- int pp,r,rr,c;
- int path[avl_max_height];
- r=avl->root; if (r==avl_none || !item) return r; // trivial case
- pp=-1;
- // 1. find node
- do {
- int v=r<<1; c=AVL_CMP1(item,r);
- if (c<0) { r=AVL_LEFT(r); } else
- if (c>0) { r=AVL_RIGHT(r); v++; }
- path[++pp]=v;
- if (c==0) break;
- } while(r!=avl_none);
- if (c<0) r=path[pp]>>1;
- if (r!=avl_none) { // c=0 found item
- r=AVL_LEFT(r);
- if (r==avl_none) {
- while(pp>0 && ((path[pp-1]&1)==0)) --pp;
- rr=pp>0 ? path[pp-1]>>1 : avl_none;
- } else {
- do { rr=r; r=AVL_RIGHT(r); } while(r!=avl_none);
- }
- } else { // no iten found & c<0
- rr=path[pp]>>1;
- }
- if (rr!=avl_none) avl->copy(avl->copy_ctx,item,AVL_ITEM(rr));
- return rr;
- }
- int avl_available(avl_t *avl) {
- return avl->limit-avl->count;
- }
- int avl_count(avl_t *avl) {
- return avl->count;
- }
Advertisement
Add Comment
Please, Sign In to add comment