// Binomial heap implementation     -bds 10/95 compiled but not tested
/* This implementation follows the presentation in CLR 
but with a "more efficient" Union operation, which admits an 
amortized analysis which is O(1) for Make-Heap, Insert, and Union,
and is O(lg n) for the other operations.
*/

#include "binomial_heap.h"
/* This header file binomial_heap.h defines the types
Heap, Treelist, Tree, Node, Key, Data.

The only operation on Heaps is "head", with signature
Treelist head(Heap H) 
It returns the list of trees in H. It is Assignable.
For example, "head(H) = head(K);"

Treelists and Trees are built from nodes:

Access operators on nodes are:
Key key(Node x),  
Data data(Node x), 
int degree(Node x) 
  is the degree of the (sub) tree rooted at x.  
  It is the number of children of x.
Node parent(Node x) 
  is NULL if x is a root, else non-null.
Node child(Node x) 
  is NULL if x is a leaf (has no children), else is the first 
  child node of x.  Siblings of child(x) are the other children of x.
Node sibling(Node x) 
  is NULL if x is the last child in the list of children of a node,
  If x is a root (parent(x) = NULL) then the sibling link points to the 
  next tree in a list of trees.
The above node access operators are all assignable.

A tree x is a binomial tree if 
0. It has no children and has degree(x) == 0, or
1. If x had degree k, The children of x have degrees k-1, k-2, ..., 0 in 
order.  More specifically,
  1a. degree(child(x)) == degree(x) - 1.
  1b. If a child c of x has degree m > 0, then sibling(c) has degree m-1 
  1c. If a child c of x has degree 0, then sibling(c) == NULL.
2. (heap property) key(x) > key(c) for all children c of x.
3. All children of x are themselves binomial trees.

Summary: In a Binomial Tree, each child list is a list of binomial TREES 
which are DECREASING by degree, and constitute 
a COMPLETE SEQUENCE numerically, starting with degree 
one less than the parent.

A tree (treelist) x is a binomial heap if 
0. x is NULL or
1. x is a binomial tree and parent(x) is NULL.
2. s = sibling(x) is (2a) also a binomial heap and (2b) either 
   s is NULL or has degree(s) > degree(x) .

Summary: A Treelist is like a child list in a binomial tree in that 
1. each node is the ROOT of a binomial tree, but except that
2. the nodes are in INCREASING order by degree, and it
3. need NOT include a COMPLETE SEQUENCE of degrees.
  
In the implementation there is no distinction between pointers to nodes
and trees.  A binomial tree is never empty, so for all 
computational purposes is equivalent to its root node.  
A list of trees, if not empty, is also associated with a node,
namely the root node of the first tree in the list. The
other nodes in the list are accessed by following the sibling
link of that first tree.  We use the three equivalent types
"Node*", "Tree", and "Treelist" to emphasize the way in which 
a node is being viewed in the particular context.

the type Key admits comparison operations, < , <=, etc, and has the 
special values infinity and -infinity, where infinity is guaranteed
to be greater than any actual key in use, and -infinity is guaranteed
to be less.

   Heap functions meant for applications

Heap  Make_Binomial_Heap()
void  Binomial_Heap_Insert(Heap H, Key k, Data d); // k,d inserted into H
Node* Binomial_Heap_Minimum(Heap H);
void  Binomial_Heap_Union(Heap H1, Heap H2); // H1 = H1 U H2
Node* Binomial_Heap_Extract_Minimum(Heap H);
void  Binomial_Heap_Decrease_Key(Node* x, Key k);
void  Binomial_Heap_Delete(Heap H, Node* x);

   Additional support functions 
void  Binomial_Link(Tree y, Tree z);
Treelist Reversed_Sibling_List(Treelist c);

Make_Binomial_Heap() is defined in the header file

All the functions defined in the header file work in O(1) time.
This includes Make_Binomial_Heap() and all the access functions such as head(H),
key(x), etc.

This concludes the discussion of the general setup and of the header file.

The following functions are declared in binomial_heap.h 
and are defined here. 
*/

void Binomial_Heap_Insert(Heap H, Key k, Data d)
  {
  Heap S = Make_Binomial_Heap();
  head(S) = new(Node); 
  key(head(S)) = k;       data(head(S)) = d;
  child(head(S)) = NULL;  degree(head(S)) = 0;
  parent(head(S)) = NULL; sibling(head(S)) = NULL;
  Binomial_Heap_Union(H, S);
  }

Node* Binomial_Heap_Minimum(Heap H)
// Assume H is a nonempty heap.  Return the node with minimum key from H.
// It will be one of the roots of the binomial trees in H.
  {
  Key min = infinity; Node* ans = NULL; 
  // check all root keys in the treelist.
  for (Treelist x = head(H); x != NULL; x = sibling(x))
    if (key(x) < min) 
      {min = key(x); ans = x;}
  return ans;
  }

void Binomial_Link(Tree y, Tree z)
// Asumes y and z are binomial trees of the same degree k.
// Joins them in a binomial tree of degree k+1 rooted at z.
// Hence, the resulting tree replaces z in the treelist it was in, if any.
  {
  if ( key(y) < key(z) )
    {
    Key tk = key(z); key(z) = key(y); key(y) = tk;
    Data td = data(z); data(z) = data(y); data(y) = td;
    Node* tc = child(z); child(z) = child(y); child(y) = tc;
    }

  parent(y) = z; sibling(y) = child(z); child(z) = y; degree(z)++ ;
  // Note: sibling(z) is unchanged, 
  // i.e. z's membership in a treelist is unaffected.
  }

/* Next we have a more efficient Union algorithm than given in CLR.
The efficiency is in that it does not process trees in the heap with 
higher degree trees beyond those that interact with the trees in the heap
with lower maximum degree tree.
*/

void Binomial_Heap_Union(Heap H1, Heap H2)
// Modify H1 into the union of H1 and H2.  H2 is destroyed in the process.
  {
  Node* x; Node* y; Node* z;
  Treelist L1 = head(H1); Treelist L2 = head(H2);
  if (L1 == NULL) 
    {head(H1) = L2; return;}
  if (L2 == NULL)
    return;

//Phase 1. Merging two lists to a single list, maintaining heap properties.
  y = L1; L1 = sibling(L1);
  z = L2; L2 = sibling(L2);
  if ( degree(y) < degree(z) )
    { x = y; y = z; }
  else
    { x = z; } ////// this line was incorrectly: "{ x = z; y = x; }" ////////
  head(H1) = x;
// invariant 1: at all times, x is the current last node 
//              in the treelist of the eventual output, H1. 
// invariant 2: degree(x) <= degree(y) and both <= degrees in L1 and L2.
  while (L1 != NULL && L2 != NULL) 
    {  
// Step 1. find next element z, advancing one of the lists.
    if ( degree(L1) < degree(L2) )
      { z = L1; L1 = sibling(L1); }
    else
      { z = L2; L2 = sibling(L2); }
//   invariant 3: degree(x) <= degree(y) <= degree (z) and all three
//   degrees are less than those in L1, L2, and invariant 1 still holds.

// Step 2. 3-to-2 reduction (x, y, z reduced to x, y by linking or shifting.
    if ( degree(x) < degree(y) )
      { sibling(x) = y; x = y; y = z; }
    else if ( degree(y) < degree(z) ) // && degree(x) == degree(y) 
      { Binomial_Link(y, x); y = z;} 
    else // ( degree(y) == degree(z) && degree(x) == degree(y) )
      { Binomial_Link(z, y); }
    }

//Phase 2. Combining single "carry-over" tree with remaining list tail.
  if (degree(x) < degree(y))
    {sibling(x) = y; x = y;}
  else 
    Binomial_Link(y, x);
  Treelist L = (L1 == NULL) ? L2 : L1;
// invariant 4: degree(x) <= degrees in L and invariant 1 still holds.
  while (L != NULL)
    {
    if (degree(x) < degree(L))
      {sibling(x) = L; L = NULL; }// done
    else // further "carry" possible
      {Node* w = L; L = sibling(L); Binomial_Link(w, x);}
    }
  return;
  }

// Extraction and Deletion below are exactly as in CLR

Node* Binomial_Heap_Extract_Minimum(Heap H)
// Modify H so that the node with its minimum key is removed and 
// binomial heap properties are preserved.  Return the removed node.
  {
  Node* x = Binomial_Heap_Minimum(H);
  Treelist y = head(H);
  if (y == x) 
    head(H) = sibling(y);
  else
    while (y != NULL && sibling(y) != x) 
      y = sibling(y);
  sibling(y) = sibling(x); // snip x out
  Heap Hp = Make_Binomial_Heap();
  head(Hp) = Reversed_Sibling_List(child(x));
  Binomial_Heap_Union(H, Hp);
  return x;
  }
  
Treelist Reversed_Sibling_List(Treelist c)
// Return the reverse of the sibling list c.  c is modified into the result.
  {
  Node* r = NULL; // the reversed part of the list
  while (c != NULL)
    {
    Node* x = c; c = sibling(c);
    sibling(x) = r; r = x;
    }
  return r;
  }

void Binomial_Heap_Decrease_Key(Node* x, Key k)
// Assume x is a node in a bin heap and key(x) > k.
// Make key(x) = k and restore the heap property of the heap containing x.
  {
  key(x) = k; 
  Node* y = x; Node* z = parent(y);
  while ( z != NULL && key(y) < key(z) )
    // swap keys, move up
    {
    Key tk = key(y); key(y) = key(z); key(z) = tk;
    Data td = data(y); data(y) = data(z); data(z) = td;
    y = z; z = parent(y);
    }
  }

void Binomial_Heap_Delete(Heap H, Node* x)
  {
  Binomial_Heap_Decrease_Key(x, -infinity);
  Binomial_Heap_Extract_Minimum(H);
  }

