home *** CD-ROM | disk | FTP | other *** search
- /*******************************************************************************
- +
- + LEDA 2.1.1 11-15-1991
- +
- +
- + _rb_tree.c
- +
- +
- + Copyright (c) 1991 by Max-Planck-Institut fuer Informatik
- + Im Stadtwald, 6600 Saarbruecken, FRG
- + All rights reserved.
- +
- *******************************************************************************/
-
-
- // red-black-tree ( rb-tree )
- // implementation of memberfunctions
- // mit verkettung der blaetter
-
- //------------------------------------------------------------------
-
- #include <LEDA/rb_tree.h>
-
-
- enum left_or_right { left = 0 ,right = 1, undefined = 2 };
-
- enum colour { node_red = 0 ,node_black = 1 ,leaf_red = 2 , leaf_black = 3 , unknown = 4 };
-
- class rb_tree_node;
-
-
- rb_tree_node* rb_tree::next_item(rb_tree_node* p) const
- { rb_tree_node* x = p->son[right];
- return (x == list_ptr) ? 0 : x;
- }
-
-
- //------------------------------------------------------------------
- // next_smaller(x) : gibt zeiger auf den knoten mit key x zurueck
- // falls dieser nicht exist. sucht er den knoten mit key y , wobei
- // y < x und y maximal ; falls dieser auch nicht vorhanden => return 0
- //------------------------------------------------------------------
-
- rb_tree_node* rb_tree::next_smaller(ent x) const
- {
- TRACE(( "next_smaller : key : %d\n",int(x) ));
-
- rb_tree_node* p = get_node(x);
-
- if ( !p ) return 0; // baum leer
-
- if ( cmp(p->k,x) <= 0 ) return p;
- else if ( p != min() ) return p->son[left];
- else return 0;
- }
-
- //------------------------------------------------------------------
- // next_bigger(x) : gibt zeiger auf den knoten mit key x zurueck
- // falls dieser nicht exist. sucht er den knoten mit key y , wobei
- // y > x und y minimal ; falls dieser auch nicht vorhanden => return 0
- //------------------------------------------------------------------
-
- rb_tree_node* rb_tree::next_bigger(ent x) const
- {
- TRACE((" next_bigger : key : %d\n",int(x) ));
-
- rb_tree_node* p = get_node(x);
-
- if ( !p ) return 0; // baum leer
-
- if ( cmp( p->k,x ) >= 0 ) return p;
- else if ( p != max() ) return p->son[right];
- else return 0;
- }
-
- // by sn :
-
- rb_tree_node* rb_tree::lookup(ent x) const
- { rb_tree_node* p = get_node(x);
- if ( !p ) return 0;
- if ( cmp( p->k,x ) == 0 ) return p;
- else return 0;
- }
-
- void rb_tree::change_inf(rb_tree_node* p,ent y)
- { clear_inf(p->e);
- copy_inf(y);
- p->e = y;
- }
-
-
- //------------------------------------------------------------------
- // get_node1(x) : gibt pointer auf das blatt zurueck , das bei der suche
- // nach dem element mit key x gefunden wird
- // falls treesize = 0 => pointer = 0
- // mit cmp-function
- //------------------------------------------------------------------
-
- rb_tree_node* rb_tree::get_node1(ent x) const
-
- {
- TRACE(("get_node1 : key :%d\n",int(x) ));
-
- rb_tree_node* p;
- if ( p = root) // p:=root; if ( p != 0) continue
- while ( p->is_node() )
- p = (cmp(x,p->k) <= 0) ? p->son[left] : p->son[right] ;
- return p;
- }
-
-
- //----------------------------------------------------------------------
- // member(x) : true ,falls element with key x im baum , sonst 0
- //----------------------------------------------------------------------
-
- int rb_tree::member(ent x) const
- {
- TRACE(("member : key :%d\n",int(x) ));
-
- rb_tree_node* p = get_node(x);
- return ( p && ( cmp(p->k,x) == 0 ) ) ? true : false ;
- }
-
- //------------------------------------------------------------------
- // access(x) : gibt eintrag des elements mit key x zurueck
- //------------------------------------------------------------------
-
- ent& rb_tree::access(ent x)
-
- {
- TRACE(("access : key :%d\n",int(x) ));
-
- rb_tree_node* p = get_node(x);
- if ( p && ( cmp(x,p->k) == 0 ) )
- return p->e;
- else error_handler(1," access(x) ,but no element with key x in tree ");
- }
-
-
- //----------------------------------------------------------------------
- // search :
- //----------------------------------------------------------------------
- // prog.34 in mehlhorn page 192
- // wird fuer insert und delete benoetigt . gibt Stack zurueck, worin
- // pfad von wurzel zum blatt (inkl.) gespeichert ist
- //
- // search : version mit cmp-function
- //----------------------------------------------------------------------
-
- rb_tree_node* rb_tree::search(ent x)
- {
- TRACE(("search : key : %d \n",int(x) ));
-
- // s.n.: result = inner node with key x (nil if not existing)
-
- rb_tree_node* result=nil;
-
- st.clear();
-
- rb_tree_node* p = root ;
- if ( p ) // p:=root; if ( p != 0) continue
- { while ( p->is_node() ) // else Stack remains empty
- { int rel = cmp(x,p->k);
- if ( rel <= 0 )
- { if ( rel == 0 ) result = p;
- push(p,left);
- p = p->son[left];
- }
- else { push(p,right);
- p = p->son[right];
- }
- }
- push(p,undefined); //leaf on the top of Stack
- }
- return result;
- }
-
- //----------------------------------------------------------------------
- // pop() : private memberfunktion ( fuer insert,delete )
- //----------------------------------------------------------------------
-
- void rb_tree::pop(rb_tree_node_ptr& q, int& dir1)
- {
- TRACE(("pop betreten : leerer keller : %s \n", st.empty() ? "ja" : "nein" ));
-
- stack_el z = st.pop();
- q = z.nodeptr;
- dir1 = z.dir;
-
- TRACE(("pop verlassen: key : %d :dir : %d :leerer keller : %s \n" ,int(q->k),dir1, st.empty() ? "ja" : "nein"));
- }
-
- //----------------------------------------------------------------------
- // rotation : private memberfunktion ( fuer insert,delete )
- //----------------------------------------------------------------------
-
- void rb_tree::rotation(rb_tree_node* p,rb_tree_node* q, int left_right)
- {
- TRACE(("rotation\n"));
-
- p->son[left_right] = q->son[1-left_right];
- q->son[1-left_right] = p;
- }
-
-
- //----------------------------------------------------------------------
- // double_rotation : private memberfunktion ( fuer insert, delete )
- //----------------------------------------------------------------------
-
- void rb_tree::double_rotation(rb_tree_node* p, rb_tree_node* q, rb_tree_node* r,
- int dir1, int dir2)
- {
- TRACE(("double_rotation\n"));
-
- p->son[dir1] = r->son[dir2];
- q->son[dir2] = r->son[dir1];
- r->son[dir1] =q;
- r->son[dir2] =p;
- }
-
- //----------------------------------------------------------------------
- // if_root : falls p == root => root = q
- // sonst haenge q an frueheren vater von p ( den vater
- // erhaelt man durch pop )
- //----------------------------------------------------------------------
-
- void rb_tree::if_root(rb_tree_node* p,rb_tree_node* q)
- {
- TRACE(( "if_root \n"));
-
- int dir;
-
- if ( p == root ) root = q;
- else {
- TRACE((" if_root :Stacksize ist %d\n", st.size() ));
- pop(p,dir);
- p->son[dir] = q;
- }
- }
-
- //----------------------------------------------------------------------
- // insert(x,y) : prog. 35/36/37 in mehlhorn seite 193
- // fuegt element mit key x und entry y ein
- // gibt zeiger auf eingefuegten knoten zurueck
- //----------------------------------------------------------------------
-
- rb_tree_node* rb_tree::insert( ent x, ent y)
- {
- TRACE(("insert : key = %d \n" , int (x) ));
-
- copy_key(x);
- copy_inf(y);
-
- rb_tree_node* q = new rb_tree_node(x,y,leaf_black,0,0);
- rb_tree_node* r = new rb_tree_node;
- rb_tree_node* p;
- rb_tree_node* back = q; // wird von insert zurueckgegeben
- int dir1,dir2;
-
- ++ counter;
-
- if ( !root )
- {
- delete r;
- list_ptr = root = q;
- root->son[right] = root->son[left] = root; // verkettung
- return back ;
- }
-
- search(x); // danach steht im Stack st der suchpfad
-
- pop(p,dir1);
-
- if ( cmp(p->k,x) == 0 )
- // falls element mit gleichem
- { // key exist. => ueberschreiben
- delete r;
- delete q;
- --counter;
- p->e = y;
- return p;
- }
-
- r->gets_red_node();
- if ( cmp(x,p->k) < 0 )
- { r->k = x;
- r->son[left] = q;
- r->son[right]= p;
-
- q->son[left] = p->son[left]; // verkettung
- q->son[right] = p;
- p->son[left]->son[right] = q;
- p->son[left] = q;
- if ( p == list_ptr ) list_ptr = q;
- // p->key war minimum , x neues minimum
-
- }
- else
- { r->k = p->k;
- r->son[left] = p;
- r->son[right]= q;
-
- q->son[left] = p; // verkettung
- q->son[right] = p->son[right];
- p->son[right]->son[left] = q;
- p->son[right] = q;
- }
-
- if ( st.empty() ) // baum vor einfuegen einelementig
- {
- r->gets_black_node();
- root = r;
- p->son[right] = p->son[left] = q; // verkettung
- return back ;
- }
-
- pop(q,dir2);
- q->son[dir2] = r;
- if ( q->is_black() ) return back; // end of prog.35 in mehlhorn
-
- while (1)
- {
- pop(p,dir1);
-
- if ( p->son[1-dir1]->is_red() ) //p hat 2 rote soehne=> farbtausch
- {
- p->son[left]->gets_black_node();
- p->son[right]->gets_black_node();
- p->gets_red_node();
- if ( p == root ) { p->gets_black_node(); return back; }
- r = p;
- pop(q,dir2);
- if ( q->is_black() ) return back;
- }
- else if (dir1 == dir2) // rebalancieren durch eine rotation
- {
- rotation(p,q,dir1);
- p->gets_red_node();
- q->gets_black_node();
- if_root(p,q);
- return back;
- }
- else
- {
- double_rotation(p,q,r,dir1,dir2);
- p->gets_red_node();
- r->gets_black_node();
- if_root(p,r);
- return back;
- }
- }
- }
- //----------------------------------------------------------------------
- // end of insert
- //----------------------------------------------------------------------
-
-
- //----------------------------------------------------------------------
- // del(x) :
- // loescht element mit key x und gibt entry dieses elements zurueck,
- // falls ein solches existiert , sonst 0 .
- //----------------------------------------------------------------------
-
- void rb_tree::del(ent x)
- {
- TRACE(("del : %d \n",int(x) ));
-
- rb_tree_node_ptr u,v,w,p,x1,y;
- int dir1,dir2;
-
- if ( !root ) return; // error_handler(2, " del , but treesize = 0 ");
-
-
- rb_tree_node* pp = search(x); // danach im Stack st der suchpfad gespeichert
- // pp ist innerer Knoten mit Kopie von x
- // (nil, falls keiner existiert)
-
-
- pop(v,dir1);
-
- if ( cmp(v->k,x) != 0 ) return; // x nicht gefunden: nichts zu tun
-
-
- -- counter;
-
- rb_tree_node* back = v; // back ist zu entfernendes Blatt
-
- if ( v == root ) // treesize = 1
- {
- root = list_ptr = 0;
- clear_key(back->k);
- clear_inf(back->e);
- delete back;
- return;
- }
-
- //s.n.: overwrite possible copy of x in inner node pp
-
- if (pp && v->son[left]) pp->k = v->son[left]->k;
-
-
- if ( v == list_ptr ) list_ptr = v->son[right];
- v->son[left]->son[right] = v->son[right]; // verkettung
- v->son[right]->son[left] = v->son[left];
-
- pop(u,dir1);
- if (st.empty() ) // u = root
- {
- root = u->son[1-dir1];
- if ( root->is_node() ) // tree hat zwei blaetter
- root->gets_black_node();
- else // tree besteht nur noch aus root
- root->gets_black_leaf();
-
- delete(u);
- clear_key(back->k);
- clear_inf(back->e);
- delete back;
- return;
- }
-
- pop(p,dir2);
- w = u->son[1-dir1];
- p->son[dir2] = w;
- if (u->is_red() || w->is_red() ) // situation 1 , 2
- {
- TRACE(( " situation 1,2 \n " ));
-
- if ( w->is_red() ) w->gets_black_node();
- delete(u);
- clear_key(back->k);
- clear_inf(back->e);
- delete back;
- return;
- }
- delete(u);
-
- // situation 3 : schwarztiefe des unterbaums mit wurzel v um
- // zu niedrig
- // => tiefe im unterbaum mit wurzel v um 1 erhoehen
- // bzw. v wandert weiter nach oben
- // bem: u ist vater von v , w der bruder von v
-
- v = w;
- u = p;
- dir1 = dir2;
- while(1)
- {
- w = u->son[1-dir1];
- if ( w->is_black() ) // fall2 , v und bruder w sind black
- { if ( w->son[1-dir1]->is_red() ) // fall 2.b
- {
- TRACE((" 2b \n"));
- rotation(u,w,1-dir1);
- w->c = u->col();
- u->gets_black_node();
- (w->son[1-dir1])->gets_black_node();
- if_root(u,w);
- clear_key(back->k);
- clear_inf(back->e);
- delete back;
- return;
- }
- else if ( ( y = w->son[dir1] )->is_red() ) // 2.c
- {
- TRACE((" 2c \n"));
- double_rotation(u,w,y,1-dir1,dir1);
- y->c = u ->col();
- u->gets_black_node();
- if_root(u,y);
- clear_key(back->k);
- clear_inf(back->e);
- delete back;
- return;
- }
- else if ( u->is_red() ) // fall 2.a2
- {
- TRACE((" 2a2 \n"));
- w->gets_red_node();
- u->gets_black_node();
- clear_key(back->k);
- clear_inf(back->e);
- delete back;
- return;
- }
- else { // fall 2.a1
- TRACE((" 2a1 \n"));
- rotation(u,w,1-dir1);
- u->gets_red_node();
- if ( u == root )
- {
- TRACE((" 2a1 nicht ende\n"));
- root = w ;
- clear_key(back->k);
- clear_inf(back->e);
- delete back;
- return;
- }
- else {
- TRACE((" 2a1 ende\n"));
- pop(u,dir1);
- u->son[dir1] = w;
- v = w;
- }
- // einziger fall , der nicht sofort (d.h.nach einfach-
- // oder doppelrotation) terminiert ; v wandert zur wurzel
- }
- }
- else // fall 3 ; v ist black, w ist red
- { x1 = w->son[dir1];
- if ( x1->son[1-dir1]->is_red() ) // fall 3.b
- {
- TRACE((" 3b \n"));
- double_rotation(u,w,x1,1-dir1,dir1);
- w->son[dir1]->gets_black_node();
- if_root(u,x1);
- clear_key(back->k);
- clear_inf(back->e);
- delete back;
- return;
- }
- else if ( ( y = x1->son[dir1] )->is_red() ) // fall 3.c
- {
- TRACE((" 3c \n"));
- rotation(x1,y,dir1);
- w->son[dir1] = y;
- double_rotation(u,w,y,1-dir1,dir1);
- y->gets_black_node();
- if_root(u,y);
- clear_key(back->k);
- clear_inf(back->e);
- delete back;
- return;
- }
- else // fall 3.a
- {
- TRACE((" 3a \n"));
- rotation(u,w,1-dir1);
- w->gets_black_node();
- x1->gets_red_node ();
- if_root(u,w);
- clear_key(back->k);
- clear_inf(back->e);
- delete back;
- return;
- }
- } // end of fall 1,2,3
- } // end of while(1)
- } // end of del
-
-
- //------------------------------------------------------------------
- // operator=
- //------------------------------------------------------------------
-
- rb_tree& rb_tree::operator=(const rb_tree& t)
- {
- TRACE(( " operator= \n"));
-
- if (this == &t) return *this;
-
- clear();
-
- if ( t.root )
- { rb_tree_node* pre = 0;
- root = t.copy_tree(t.root,pre);
- list_ptr = root;
- while (list_ptr->son[left]) list_ptr = list_ptr->son[left];
- list_ptr->son[left] = pre;
- pre->son[right] = list_ptr;
- counter = t.counter;
- }
-
- return *this;
- }
-
- //------------------------------------------------------------------
- // rb_tree(rb_tree&) constructor :
- //------------------------------------------------------------------
-
- rb_tree::rb_tree(const rb_tree& t) : st(32)
- { root = list_ptr = 0 ;
- if ( t.root )
- { rb_tree_node* pre = 0;
- root = t.copy_tree(t.root,pre);
- list_ptr = root;
- while (list_ptr->son[left]) list_ptr = list_ptr->son[left];
- list_ptr->son[left] = pre;
- pre->son[right] = list_ptr;
- counter = t.counter;
- }
- }
-
- //------------------------------------------------------------------
- // copy_tree(p) kopiert baum mit wurzel p und gibt pointer auf wurzel
- // der kopie zurueck. pre enthaelt letztes erzeugtes Blatt ( Blaetter
- // werden von links nach rechts erzeugt!
- //------------------------------------------------------------------
-
- rb_tree_node* rb_tree::copy_tree( rb_tree_node* p, rb_tree_node_ptr& pre) const
- {
- rb_tree_node* q = new rb_tree_node(p); // q = p
-
- if ( p->is_node() ) // internal node: copy subtrees
- {
- q->son[left] = copy_tree(p->son[left],pre);
- q->son[right] = copy_tree(p->son[right],pre);
- }
- else //leaf: chaining with last created leaf "pre"
- {
- copy_key(q->k);
- copy_inf(q->e);
-
- if (pre) pre->son[right] = q;
- q->son[left] = pre;
- pre = q;
-
- }
-
- return q;
- }
-
- //------------------------------------------------------------------
- // clear
- //------------------------------------------------------------------
-
- void rb_tree::clear()
- {
- TRACE(( " clear \n"));
-
- st.clear();
-
- if ( root )
- {
- del_tree(root);
- root = list_ptr = 0;
- counter = 0;
- }
- }
-
- //------------------------------------------------------------------
- // del_tree(p) : loeschen des unterbaums mit wurzel p
- //------------------------------------------------------------------
-
- void rb_tree::del_tree(rb_tree_node* p)
- {
- TRACE(("del_tree : nodekey :%d \n",int(p->k) ));
-
- if ( p->is_node() )
- { del_tree(p->son[left]);
- del_tree(p->son[right]);
- }
- else
- { clear_key(p->k);
- clear_inf(p->e);
- }
-
- delete(p);
- }
-
- //-----------------------------------------------------------------
- // test auf schwarztiefe und bildhafte darstellung des baums nur
- // im Trace-modus moeglich
- //-----------------------------------------------------------------
-
- #ifdef TEST1
-
- int rb_tree::deep_test(rb_tree_node* p) const
- {
- if ( p->is_node() )
- {
- int i = deep_test(p->son[left]);
- if ( i && i == deep_test( p->son[right] ) )
- // falls i=0 => fehler im linken sohn
- return ( p->is_black() ? i+1 : i ) ;
- else return false ; // fehler => return false = 0
- }
- else return 1; // p ist blatt ( immer black )
- }
-
- int rb_tree::black_deep_test() const
- {
- if ( root ) // falls treesize > 0
- return ( deep_test(root) ? true : false ) ;
- else return true;
- }
-
- //------------------------------------------------------------------
- // print() : ausgeben des rb_trees ( um 90 grad gedreht )
- // nur fuer type = int
- // print_tree(p) : ausgeben des unterbaums mit wurzel p
- //------------------------------------------------------------------
-
- void rb_tree::print_tree(rb_tree_node* p,int h) const
- {
- if ( p->is_node() ) print_tree(p->son[right],h+1);
-
- for( int j=1; j <= h ; j++ ) cout << " ";
-
- switch (p->col()) {
- case node_black : cout << " b "; break;
- case leaf_black : cout << " b "; break;
- case node_red : cout << " r "; break;
- case leaf_red : cout << " r "; break;
- case unknown : cout << " u "; break;
- default : cout << " ? "; break;
- }
- cout << int(key(p)) ;
- if ( p->is_leaf() )
- {
- cout << string(" succ : %d",int(key(p->son[right]))) ;
- cout << string(" pred : %d\n",int(key(p->son[left]))) ;
- }
- else cout << "\n";
-
- if ( p->is_node() ) print_tree(p->son[left],h+1);
- }
-
- void rb_tree::print() const
- {
- cout << "tree.size : " << size() << "\n";
- if ( root ) print_tree(root,1);
- }
-
- #endif TEST1
-
-
- void rb_tree::draw(DRAW_RB_NODE_FCT draw_red_node,
- DRAW_RB_NODE_FCT draw_black_node,
- DRAW_RB_EDGE_FCT draw_edge,
- rb_tree_node* r,
- double x1, double x2, double y,
- double ydist, double last_x)
- {
-
- double x = (x1+x2)/2;
-
- if (r==nil) return;
-
- if (last_x != 0) draw_edge(last_x,y+ydist,x,y);
-
- if (r->is_red())
- draw_red_node(x,y,r->k);
- else
- draw_black_node(x,y,r->k);
-
- if (r->is_node())
- { draw(draw_red_node,draw_black_node,draw_edge,r->son[0],x1,x,y-ydist,ydist,x);
- draw(draw_red_node,draw_black_node,draw_edge,r->son[1],x,x2,y-ydist,ydist,x);
- }
- }
-
-
- void rb_tree::draw(DRAW_RB_NODE_FCT draw_red_node,
- DRAW_RB_NODE_FCT draw_black_node,
- DRAW_RB_EDGE_FCT draw_edge,
- double x1, double x2, double y, double ydist)
- { draw(draw_red_node,draw_black_node,draw_edge,root,x1,x2,y,ydist,0); }
-
-
- //------------------------------------------------------------------
- // end of rb_tree.c
- //------------------------------------------------------------------
-