type  balance = ( L, B, R );

      LINK = ^Branch;

      Branch  = record
                 leaf     : data;
                 left     : LINK;
                 right    : LINK;
                 bal      : balance;
                end;


{ ***********   CONSTANTS, AND VARIABLES FOR AV Lists ********** }

const on_bit  : array[0..15] of word =
                ( $0001,$0002,$0004,$0008,$0010,$0020,$0040,$0080,
                  $0100,$0200,$0400,$0800,$1000,$2000,$4000,$8000 );
      off_bit : array[0..15] of word =
                ( $FFFE,$FFFD,$FFFB,$FFF7,$FFEF,$FFDF,$FFBF,$FF7F,
                  $FEFF,$FDFF,$FBFF,$F7FF,$EFFF,$DFFF,$BFFF,$7FFF );
      depth : integer = -1;
      h     : integer = 0;      { Set by recursive calls to search to
                               indicate that the tree has grown.
                               It will magically change its value
                               everytime ins() is called recursively. }

var  Newnode,
     Conflicting,
     AvlKey,
     root,
     tbranch,
     p            : LINK;
     Notfound     : boolean;
     map : array[0..1023] of integer;
     n,i : integer;
     


{ ***********   SPECIFIC PROCEDURES AND FUNCTION FOR AV Lists ********** }

function talloc: LINK;
var p : LINK;
begin
  New(p);
  if p <> NIL then
    with p^ do
    begin
      left := NIL;
      right := NIL;
      bal   := B;
    end;
  talloc := p;
end;

procedure tfree( var p : LINK);
begin
  dispose(p);
end;

function testbit(c: integer): integer;
begin
 testbit := Map[ c SHR 4] AND (on_bit[c AND $0F]);
end;

procedure  setbit( c, val : integer);
begin
   if (val <> 0)
   then
      Map[c SHR 4] := Map[c SHR 4] OR (on_bit[(c AND $0F)])
   else
      Map[c SHR 4] := Map[c SHR 4] AND (off_bit[(c AND $0F)]) ;
end;

procedure trav(root : LINK; direction: balance; device : integer);
label trav_exit;
var i : integer;
begin
   if (root <> NIL) AND (escape = FALSE) then
   begin
     depth := depth + 1;
     if (root^.left <> NIL)
       then trav(root^.left,R, device)
       else setbit(depth + 1,1);
     if (escape = TRUE) then goto trav_exit;
     if device = 0 then print(root^.leaf)
                   else fprint(root^.leaf);
     if direction = L then setbit(depth, 0)
                      else setbit(depth, 1);
     if (root^.right <> NIL)
     then  trav(root^.right, L, device)
     else  setbit(depth + 1, 0);
     depth := depth - 1;
   end;
trav_exit:
end;

procedure tprint(root : LINK);
var i : integer;
begin
   escape := FALSE;
   for i := 0 to 1023 do map[i] := 0;
   depth := -1;
   trav( root, R, 0);
end;

function find( root, key : LINK ): LINK;
begin
   if ( root = NIL )
     then  find := NIL
     else  case cmp( key^.leaf, root^.leaf) of
             -1 : find := find(root^.left, key);
              0 : find := root;
              1 : find := find(root^.right, key);
           end;
end;

procedure ins( var pp : LINK );
var  p, p1, p2 : LINK;
begin
   p := pp;
   if ( p = NIL )
   then
     begin
        p := Newnode;
        h := 1;
     end
   else
     case cmp(newnode^.leaf, p^.leaf) of
        0 : Conflicting := p;
       -1 : begin
              ins( p^.left );
              if ( h > 0 ) then
              case p^.bal of
                 R: begin
                      p^.bal := B;
                      h := 0;
                    end;
                 B: p^.bal := L;
                 L: begin
                      p1 := p^.left;
                      if ( p1^.bal = L )
                      then begin
                             p^.left   := p1^.right;
                             p1^.right := p;
                             p^.bal    := B;
                             p         := p1;
                           end
                      else begin
                             p2          := p1^.right;
                             p1^.right   := p2^.left;
                             p2^.left    := p1;
                             p^.left     := p2^.right;
                             p2^.right   := p;
                             if (p2^.bal = L)
                               then p^.bal := R
                               else p^.bal := B;
                             if (p2^.bal = R)
                               then p1^.bal := L
                               else p1^.bal := B;
                             p := p2;
                           end;
                      p^.bal := B;
                      h      := 0;
                    end;
              end;
            end;
        1 : begin
              ins( p^.right );
              if ( h > 0 ) then
              case  p^.bal  of
                L: begin
                     p^.bal := B;
                     h := 0;
                   end;
                B: p^.bal := R;
                R: begin
                     p1 := p^.right;
                     if ( p1^.bal = R )
                     then
                       begin
                         p^.right := p1^.left;
                         p1^.left := p;
                         p^.bal   := B;
                         p        := p1;
                       end
                     else
                       begin
                         p2        := p1^.left;
                         p1^.left  := p2^.right;
                         p2^.right := p1;
                         p^.right  := p2^.left;
                         p2^.left  := p;
                         if (p2^.bal = R)
                           then p^.bal := L
                           else p^.bal := B;
                         if (p2^.bal = L)
                           then p1^.bal := R
                           else p1^.bal := B;
                         p           := p2;
                       end;
                    p^.bal := B;
                    h      := 0;
                  end;
              end;
            end;
     end;
     pp := p;
end;

procedure insert( var rootp, netbrnch : LINK);
begin
{ Insert newnode into tree pointed to by rootp.  Cmp is passed
  Return NIL on success or a pointer to the conflicting node
  on error.
}
   h := 0;
   Newnode := netbrnch;
   Conflicting := NIL;
   ins(rootp);
   if Conflicting <> NIL then tfree(netbrnch);
end;

function balance_l( var pp : LINK ): boolean;

{ This routine is called when the left branch of the current
  subtree (pointed to by p) has shrunk.  It adjusts the balance
  factors and rebalances if necessary, modifying *pp to point
  at the new root (after the rebalance).  Returns TRUE if the
  tree got smaller as a result of the delete or the rebalance
  operation, else returns 0.
}
var p, p1, p2 : LINK;
    b1, b2    : balance;
    got_smaller : boolean;

begin
  got_smaller := TRUE;
  p := pp;
  case p^.bal of
    L: p^.bal := B;
    B: begin
         p^.bal := R;
         got_smaller := FALSE;
       end;
    R: begin
         p1 := p^.right;
         b1 := p1^.bal;
         if ( b1 <> L )
         then begin
                p^.right := p1^.left;
                p1^.left := p;
                if ( b1 <> B )
                then begin
                       p^.bal := B;
                       p1^.bal := B;
                     end
                else begin
                       p^.bal := R;
                       p1^.bal := L;
                       got_smaller := FALSE;
                     end;
                p := p1;
              end
            else begin
                   p2         := p1^.left;
                   b2         := p2^.bal;
                   p1^.left   := p2^.right;
                   p2^.right  := p1;
                   p^.right   := p2^.left;
                   p2^.left   := p;
                   case b2 of
                     R    : p^.bal := L;
                     B, L : p^.bal := B;
                   end;
                   case b2 of
                     L    : p1^.bal := R;
                     B, R : p1^.bal := B;
                   end;
                   p           := p2;
                   p2^.bal     := B;
                 end;
       end;
   end;
   pp := p;
   balance_l := got_smaller;
end;


function balance_r( var pp : LINK ): boolean;
{ same as balance_l, but is called when a right subtree has
  been made smaller.
}
var p, p1, p2 : LINK;
   b1, b2     : balance;
   got_smaller : boolean;
begin
  got_smaller := TRUE;
  p := pp;
  case p^.bal of
    R: p^.bal := B;
    B: begin
         p^.bal := L;
         got_smaller := FALSE;
       end;
    L: begin
         p1 := p^.left;
         b1 := p1^.bal;
         if ( b1 <> R )
         then begin
                p^.left     := p1^.right;
                p1^.right   := p;
                if ( b1 <> B )
                then p^.bal := B
                else begin
                       p^.bal      := L;
                       p1^.bal     := R;
                       got_smaller := FALSE;
                     end;
                p := p1;
              end
         else begin
                p2          := p1^.right;
                b2          := p2^.bal;
                p1^.right   := p2^.left;
                p2^.left    := p1;
                p^.left     := p2^.right;
                p2^.right   := p;
                case b2 of
                  L   : p^.bal := R;
                  B,R : p^.bal := B;
                end;
                case b2 of
                  R   : p1^.bal := L;
                  B,L : p1^.bal := R;
                end;
                p           := p2;
                p2^.bal     := B;
              end;
       end;
  end;
  pp := p;
  balance_r := got_smaller;
end;

function descend( var  rootp, dpp : LINK): boolean;
{ rootp     address of root of current node
  dpp       address of node to be deleted

  Does the actual delete when the root node has both left and
  right descendents.  Descends to the rightmost node of the left
  subtree and then copies the contents of that node to the
  node-to-be-deleted (dpp).  Then the node-to-be-deleted is
  modified to point to the former rightmost node.
}
begin
  if ( rootp^.right <> NIL )
  then
    case descend( rootp^.right, dpp) of
      FALSE  : descend := FALSE;
      TRUE   : descend := balance_r(rootp) ;
    end
  else begin
         move(rootp^.leaf,dpp^.leaf,sizeof(data));
         dpp := rootp;
         rootp := rootp^.left;
         descend := TRUE;
       end;
end;

function del(var  rootp : LINK ): boolean;
{
  Delete AvlKey from tree pointed to by rootp.  Return TRUE if the size
  of the tree has been reduced, FALSE otherwise.
}
var  dp : LINK;      { pointer to node to delete }
     got_smaller : boolean;
begin
   got_smaller := FALSE;  { set TRUE if tree shrinks  }
   if ( rootp = NIL )
   then Notfound := TRUE
   else begin
          case cmp(AvlKey^.leaf, rootp^.leaf) of
            -1 : if ( del(rootp^.left) = TRUE )
                 then got_smaller := balance_l( rootp ) ;
             1 : if ( del(rootp^.right) = TRUE )
                 then got_smaller := balance_r( rootp ) ;
             0 : begin
                   case check_if_ok(rootp^.leaf) of
                     -1 : Notfound := TRUE;
                      0 : if (del(rootp^.right) = TRUE)
                          then got_smaller := balance_r(rootp);
                      1 : begin
                            dp := rootp;
                            if ( dp^.right = NIL )
                            then begin
                                   rootp      := dp^.left;
                                   got_smaller := TRUE;
                                 end
                            else if ( dp^.left = NIL )
                                 then begin
                                        rootp := dp^.right;
                                        got_smaller := TRUE;
                                      end
                                 else if ( descend(rootp^.left, dp ) = TRUE )
                                      then got_smaller := balance_l( rootp ) ;
                            tfree( dp );
                          end;
                   end;
                 end;
           end;
         end;
  del := got_smaller;
end;


function  delete( var rootp, pass : LINK ): boolean;
var dmy : boolean;
{
  Cmp is a comparison routine with two leaf records passed to
  it.  It should return

       -1 if key < node;
        0 if key = node;
        1 if key > node.

  DELETE returns 1 if the node was deleted,
                 0 if the node wasn't in the tree.
}
begin
  AvlKey := pass;
  Notfound := FALSE;
  dmy :=  del( rootp );
  delete := NOT Notfound;
end;

