// rbt.h  Dictionary class implementated by red-black tree method.
// based on Sedgwick, Algorithms in C++, chapter 15         -saunders 2/96
//                                            templatized 3/00, -bds
#ifndef rbt_
#define rbt_
#include <iostream.h>

#define debug(s, v) 
//#define debug(s, v) (cerr << (s) << (v) << '\n')

/***************************************************************** 
This red-black tree implementation is parameterized by 
a keyType and an infoType.

The keyType must be a totally ordered type including a minimum value, keyMIN, 
which will not occur in user data. I/O to streams must be supported. 
Operators required:

   keyType < keyType, 
   cout << keyType, cin >> keyType

   keyMIN < key must be true for all keys used.

The infoType must be an equality testable type including a special value, 
infoNIL, indicating no info.  I/O to streams must be supported. 
Operators required:

   infoType == infoType, infoType != infoType, 
   cout << infoType, cin >> infoType

   infoNIL != info must be true for all info used.

*****************************************************************/

template<class keyType, class infoType, 
	 const keyType keyMIN, const infoType infoNIL>
class Dict 
{public:
  Dict(int max = 0);
  ~Dict(){}
  
  ///////////////////////////
  //// The fundamental Dictionary functions are search and insert

  // search returns the info associated with key v in the dictionary.
  // It returns infoNIL if there is no associated info.
  infoType search(keyType v);

  // insert puts info in the dictionary associated with the key v.
  void insert (keyType v, infoType info);

  ///////////////////////////
  //// Aux functions display() and black_depth() are also provided.

  // display makes an ascii display of the red-black tree.
  void display (int flag); 

  // black_depth returns the current depth of the tree counting
  // only black edges.
  int black_depth();

 private:
    struct node /* your basic binary tree node + color bit */
    { keyType key; 
      infoType info;
      bool red_up; /* this being true means edge from parent is red */
      node* L; node* R; /* left and right child links */
      node(keyType k, infoType i, bool color, node* lefty, node* righty)
       {key = k; info = i; red_up = color; 
	L = lefty; R = righty;
       }
    };
    node* head;
    node* z;
    node* x; node*  p; /* variables used by insert() */
    node* g; node* gg; /* and its pawn split()       */
    void split(/* node* x, node* p, node* g, node* gg*/)
    { splits++;
      x->red_up = true;
      x->L->red_up = false; x->R->red_up = false;
      if (p->red_up)
      { g->red_up = true;
        if ((p == g->L) != (x == p->L)) p = rotate(x, p, g);
        x = rotate(p, g, gg);
        x->red_up = false;
      }
    }
    node* rotate(node* gc, node* c, node* y)
    { rotations++;
      if (c->L == gc) 
      { c->L = gc->R;  gc->R = c;}
      else
      { c->R = gc->L; gc->L = c;}
      if (y->L == c) y->L = gc; else y->R = gc;
      return gc;
    }
    int splits; int rotations; /* counters used for analysis only */

    void display_tree(node * T, int offset) /* used by display */
    { const int shift = 4;
      if (T != z) 
      { if (T->red_up) 
        { display_tree(T->R, offset);
          for (int i = 0; i < offset-shift+1; i++) cout << " ";
          cout << T->key << '\n';
          display_tree(T->L, offset); 
        }
        else 
        { display_tree(T->R, offset+shift);
          for (int i = 0; i < offset; i++) cout << " ";
          cout << T->key << '\n';
          display_tree(T->L, offset+shift); 
        } 
      }
      else 
      { /* for (int i = 0; i < offset; i++) cout << " ";
        cout << ".\n"; */ 
      } 
    }
};

template<class keyType, class infoType, 
	 const keyType keyMIN, const infoType infoNIL>
Dict<keyType, infoType, keyMIN, infoNIL>::Dict(int max = 0)
{ z = new node(keyMIN, infoNIL, false, 0, 0);
  z->L = z->R = z;
  head = new node (keyMIN, infoNIL, false, 0, z);
  splits = 0; rotations = 0;
}

template<class keyType, class infoType, 
	 const keyType keyMIN, const infoType infoNIL>
infoType Dict<keyType, infoType, keyMIN, infoNIL>::search(keyType v)
{ node* x = head->R;
  z->key = v;
  while (v < x->key || v > x->key)
    x = (v < x->key) ? x->L : x->R;
  return x->info;
}

template<class keyType, class infoType, 
	 const keyType keyMIN, const infoType infoNIL>
void Dict<keyType, infoType, keyMIN, infoNIL>::insert (keyType v, infoType info)
{ x = head; p = head; g = head;
  while (x != z)
  { gg = g; g = p; p = x; 
    x = (v < x->key) ? x->L : x->R; 
    if (x->L->red_up && x->R->red_up) split();
  }
  x = new node(v, info, true, z, z);
  if (v < p->key) 
    p->L = x;
  else 
    p->R = x;
  if (p->red_up) split(); /* in case rotations needed at the new node */
  head->R->red_up = false; /* in case we've had a split at the root */
}

template<class keyType, class infoType, 
	 const keyType keyMIN, const infoType infoNIL>
void Dict<keyType, infoType, keyMIN, infoNIL>::display (int flag) 
{ if (flag) 
  { cout << "0   1   2   3   4   5   6   7   8   9  10   <-- depths\n";
    display_tree(head->R, 0); 
  }
  cout << "There have been " << splits <<" splits and "
                             << rotations << " rotations.\n"; 
} 

template<class keyType, class infoType, 
	 const keyType keyMIN, const infoType infoNIL>
int Dict<keyType, infoType, keyMIN, infoNIL>::black_depth()
{ int d = 0; 
  for (node* x = head->R; x != z; x = x->L) if (!(x->red_up)) d++;
  return d;
}

#endif
