// 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); }