/******************************************************************************
* File: SkewBinomialHeap.hh
* Author: Keith Schwarz (htiek@cs.stanford.edu)
*
* An implementation of a priority queue backed by a skew binomial heap.  Like
* regular binomial heaps, skew binomial heaps are forests of specially-shaped
* trees based on the structure of the numeric representation of the heap size.
* Unlike regular binomial heaps, which are based on the binary numeral system,
* skew binomial heaps are based on the skew binary numeral system.  The skew
* binary numeral system has each digit take the value 2^{k+1} - 1, and each
* digit can be either 0, 1, or 2.  By convention, numbers are written in a way
* where the digit 2 must be the least-significant nonzero digit in the
* representation.  The first few numbers, written in this way, are 0, 1, 2,
* 10, 12, 20, 100, 101.  This may at first seem like a seemingly arbitrary
* pattern, but there actually is a deal of method to this madness.  To add one
* to a skew binary number, look at the last nonzero digit.  If it's a two,
* then we can use the fact that
*
*            2 * (2^{k+1} - 1) + 1 = 2^{k + 2} - 2 + 1 = 2^{k + 2}
*
* to remove the 2 digit and then increment the next digit by one.  To see this
* in action, consider the skew binary number 1011200 = 187 (dec).  We can add
* one to this number by removing the last 2, then incrementing the 1 that
* precedes it by one.  This yields 1012000 = 188(dec).  If, on the other hand,
* the last digit is not 2, then we can add one to the representation while
* enforcing our invariant by simply incrementing the 1s digit from 0 to 1 or
* from 1 to 2.  A quick inductive proof can show that this gives the proper
* mathematical quantity, as well as having all the invariants hold.
*
* The advantage of writing numbers in skew binary is that, given a suitable
* representation for the bits, any number can be incremented in worst-case
* constant time.  Suppose that we store the number as a list of the nonzero
* digits, together with tags on each indicating what position those digits
* are.  Then we can increment by one as follows:
*
* - If the last digit is a 2, then remove it.  If the next digit after the 2
*   is not in the next position, add a new digit with value 1 in the next
*   position.  Otherwise increment the digit in that position from 1 to 2.
* - Otherwise, if the last digit is a 1 in the 1s place, increment it to 2.
* - Otherwise, if the last digit is not in the 1s place, add a 1 in the 1s
*   place.
*
* This logic is a bit complex, but fortunately it can be implemented in time
* O(1).
*
* The idea behind the skew binomial heap is to store a family of heap-ordered
* trees of different "ranks" in the same way that numbers are written in skew
* binary.  There can be at most two trees of each rank, and if there are two
* trees of a given rank then that rank must be the lowest rank.  These trees
* are shaped in a way that allows them to be merged in one of two ways, either
* by a regular merge, which takes two trees of the same rank r and produces a
* new tree of rank r + 1, or by a "skew merge," which takes two trees of rank
* r and a singleton element, then produces a new tree of rank r + 1 holding
* both these trees and the new element.
*
* The structure of these trees, as developed by Chris Okasaki, is based on a
* more-or-less straightforward modification of binomial trees.  A skew
* binomial tree is defined recursively:
*
* - A skew binomial tree of order zero is a single node.
* - A skew binomial tree of order n + 1 is a skew binomial heap of order n
*   with a skew binomial tree of order n as a child, along with a list of
*   skew binomial trees of order 0 of length no greater than n + 1.
*
* Up to the part about the list of nodes, this description of a skew binomial
* tree is equivalent to a regular binomial tree.  The difference only shows up
* when we talk about skew merging.  To do a regular merge on skew binomial
* trees, we use the same logic for regular binomial tree merges - make the
* tree with the smaller root the root of the resulting tree, then add the tree
* with the larger root as a child.  In a skew merge, we do a regular merge
* first, then consider the new singleton element we're adding.  If the
* singleton is larger than the root of this new tree, we append it to the list
* of singleton nodes.  If it is smaller, we swap it with the root of the old
* tree, then add the root of the old tree as a singleton tree to the list of
* singleton nodes.
*
* This in part explains the limitation of why the list of singleton nodes
* can't be larger than size n + 1.  Each skew merge adds at most one new node
* to that list, and so after k skew merges the list can have at most k
* elements in it.
*
* Notice that because each skew binomial tree can have a list of singleton
* nodes with a variable number of nodes in it, the number of nodes in a skew
* binomial tree is not fixed.  However, it does fit in a definitive range.
* Consider any skew binomial tree of order r.  If none of the nodes in the
* tree have any nodes in their singleton list, then the tree has the same size
* and shape of a regular binomial tree, and thus has 2^r nodes.  If, on the
* other hand, every node has the maximum number of singleton nodes, we can
* prove by induction that the tree has 2^r - 1 additional nodes, for a total
* of 2^{r + 1} - 1 nodes.  The proof is as follows.  As a base case, a skew
* binomial tree of order 0 has no extra nodes, and 2^0 - 1 = 1 - 1 = 0.  For
* the inductive step, assume that for all trees of order n' < n, the maximum
* number of extra nodes in the tree (denoted E(r)) is 2^n' - 1.  Then we have
* that
*          n-1
* E(n) = ( sum  E(i) ) + n
*         i = 0
*
* This follows because the skew binomial tree of order n has children of order
* 0, 1, ..., n - 1, each of which have the maximum number of nodes, and itself
* carries n extra nodes.  Using the inductive hypothesis and rearranging, we
* get
*
*
*          n-1                 n-1
* E(n) = ( sum  E(i) ) + n = ( sum  2^i - 1) + n
*         i = 0               i = 0
*
*                              n-1
*                          = ( sum 2^i ) - n + n
*                             i = 0
*
*                              n-1
*                          = ( sum 2^i ) = 2^n - 1
*                             i = 0
*
* This last step follows from a well-known and easily verified result.
*
* The net result of this proof is that we can bound the number of nodes in a
* skew binomial tree of order n by the range [2^n, 2^{n + 1}).  This means
* that for any number k, if we partition the elements of k into a forest of
* skew binomial trees allowing for no more than two trees of each order, there
* are at most O(lg k) such trees, each of which has order at most O(lg k).
*
* Now that we know the shape of these trees and the way in which they are
* merged and skew-merged, we can start discussing basic operations of a skew
* binomial heap made of a forest of these trees.  The heap will be a forest of
* skew binomial trees with the following restrictions:
*
* - Each tree is heap-ordered.
* - There are at most two trees of any order.
* - If there are two trees of the same order, that is the lowest order of the
*   trees.
*
* Note the similarity between this definition and the way in which we write
* skew binary numbers.
*
* To find the minimum element of the skew binomial heap, we simply scan over
* all the heaps looking for the minimum element; this can be done in O(lg n)
* time, since there are at most O(lg n) trees.  To insert an element, we look
* at the two lowest-order trees in the heap.  If they have the same order, we
* skew merge them together into a tree of the next-highest order.  If not,
* then we add the new element as a tree of order 0.
*
* To merge two skew binomial heaps, we reduce the problem to one akin to a
* standard binomial heap merge.  First, we ensure that each heap has at most
* tree of each order by merging together any two trees with the same order,
* then doing a standard binomial heap "ripple-carry" operation to ensure that
* there is at most one tree of each order.  This takes time O(lg n), since
* there are at most O(lg n) trees.  Finally, we merge the two lists of trees
* together using the same logic as for binomial heaps by mimicking binary
* addition.  This also takes O(lg n) time, since there are at most O(lg n)
* trees.
*
* To dequeue the minimum element, we locate the minimum element as before and
* remove it to expose a forest of skew binomial trees, along with a list of
* singleton trees.  We then merge together the forest of trees with the top
* list of trees, which takes O(lg n) time since there are O(lg n) top-level
* trees and O(lg n) exposed trees, since if the tree whose min was removed had
* order r, there are r - 1 trees, and the maximum possible order is O(lg n).
* Finally, we call insert once for each singleton tree, and since there are at
* most O(lg n) of them and each insert takes O(1), this step completes in
* O(lg n) for a net runtime of O(lg n) for the dequeue step.
*/

#ifndef SkewBinomialHeap_Included
#define SkewBinomialHeap_Included

#include <functional> // For less
#include <algorithm>  // For for_each
#include <cassert>
#include <deque>
#include <vector>

/**
* A priority queue implemented as a skew binomial heap.  The queue always
* provides access to the smallest element it contains.
*/

template <typename T, typename Comparator = std::less<T> >
class SkewBinomialHeap {
public:
/**
* Constructor: SkewBinomialHeap();
* Usage: SkewBinomialHeap<int> myHeap;
* --------------------------------------------------------------------------
* Constructs a new, empty SkewBinomialHeap.
*/

explicit SkewBinomialHeap(Comparator comp = Comparator());

/**
* Destructor: ~SkewBinomialHeap();
* Usage: (implicit)
* --------------------------------------------------------------------------
* Deallocates the skew binomial heap, freeing all allocated memory.
*/

~SkewBinomialHeap();

/**
* Copy functions: SkewBinomialHeap(const SkewBinomialHeap& rhs);
*                 SkewBinomialHeap& operator= (const SkewBinomialHeap& rhs);
* Usage: SkewBinomialHeap<int> clone = extant;
*                              clone = extant;
* --------------------------------------------------------------------------
* Deep-copies this skew binomial heap.
*/

SkewBinomialHeap(const SkewBinomialHeap& rhs);
SkewBinomialHeap& operator= (const SkewBinomialHeap& rhs);

/**
* --------------------------------------------------------------------------
* Adds a new element to the skew binomial heap.
*/

/**
* void pop();
* Usage: sbh.pop();
* --------------------------------------------------------------------------
* Removes, but does not return, the minimum element of the skew binomial
* heap.  If the heap is empty, the behavior is undefined.
*/

void pop();

/**
* const T& top() const;
* Usage: cout << sbh.top() << endl;
* --------------------------------------------------------------------------
* Returns a reference to the smallest element in the heap.  This reference
* is only guaranteed to be valid until the next call to push() or pop(),
* or merge(), and becomes invalid if this object is merged with another.  If
* the heap is empty, the behavior is undefined.
*/

const T& top() const;

/**
* void merge(SkewBinomialTree& other);
* Usage: lhs.merge(rhs);
* --------------------------------------------------------------------------
* Updates this object to contain all of its elements, plus all of the
* elements in the other skew binomial heap.  The argument is destructively
* modified to be empty upon exit.
*/

void merge(SkewBinomialHeap& other);

/**
* size_t size() const;
* Usage: size_t s = sbh.size();
* --------------------------------------------------------------------------
* Returns the number of elements in the skew binomial heap.
*/

size_t size() const;

/**
* bool empty() const;
* Usage: while (!sbh.empty()) { ... }
* --------------------------------------------------------------------------
* Returns whether this skew binomial heap is empty.
*/

bool empty() const;

/**
* void swap(SkewBinomialHeap& other);
* Usage: lhs.swap(rhs);
* --------------------------------------------------------------------------
* Exchanges the contents of this skew binomial heap with some other skew
* binomial heap in O(1).
*/

void swap(SkewBinomialHeap& other);

private:
/* A utility class representing a skew binomial tree. */
struct Tree {
size_t            mOrder;      // The order of the tree.
std::deque<Tree*> mChildren;   // Its children, in ascending size order.
std::deque<Tree*> mSingletons; // The singleton nodes that live here.
T                 mValue;      // The value stored in this node.

/**
* Utility constructor: Tree(const T& value, size_t order);
* Usage: new Tree(value, 2);
* ------------------------------------------------------------------------
* Constructs a new skew binomial tree of the specified order and with the
* indicated value.
*/

Tree(const T& value, size_t order) : mOrder(order), mValue(value) {
// Handled in initializer list.
}
};

/* The trees in this heap. */
std::deque<Tree*> mTrees;

/* A cached count of the number of elements here. */
size_t mSize;

/* The comparator to use here. */
Comparator mComp;

/* Utility function to free a single tree. */
static void freeTree(Tree* toFree);

/* Utility function that inserts a singleton tree into the tree.  The size is
* not updated, but the underlying tree structure is.
*/

void insertSingleton(Tree* singleton);

/* Utility function that given two trees performs a standard merge on those
* trees to produce a new tree.
*/

Tree* mergeTrees(Tree* first, Tree* second);

/* Utility function that, given two list of trees, merges those trees into
* one sorted list.  More specifically, the list of trees of the first two
* arguments are merged together.  The first list of trees holds the result,
* while the second list of trees is emptied.
*/

void mergeHeaps(std::deque<Tree*>& lhs, std::deque<Tree*>& rhs);

/* Utility function that finds and returns the index of the smallest element
* in the list of trees.
*/

size_t indexOfMin() const;

/* Utility function that clones a skew binomial tree and returns the new
* tree.
*/

static Tree* cloneTree(const Tree* toClone);
};

/* * * * * Implementation Below This Point * * * * */

/* Constructor stores the indicated comparator. */
template <typename T, typename Comparator>
SkewBinomialHeap<T, Comparator>::SkewBinomialHeap(Comparator comp)
: mSize(0), mComp(comp) {
// Handled in initializer list.
}

/* Destructor walks over the trees, recursively deallocating them. */
template <typename T, typename Comparator>
SkewBinomialHeap<T, Comparator>::~SkewBinomialHeap() {
std::for_each(mTrees.begin(), mTrees.end(), &SkewBinomialHeap::freeTree);
}

/* Freeing a tree involves freeing its singletons and its children. */
template <typename T, typename Comparator>
void SkewBinomialHeap<T, Comparator>::freeTree(Tree* toFree) {
/* If the there is no tree, don't free anything. */
if (!toFree) return;

/* Free the tree's singletons. */
std::for_each(toFree->mSingletons.begin(), toFree->mSingletons.end(),
&SkewBinomialHeap::freeTree);

/* Free the tree's children. */
std::for_each(toFree->mChildren.begin(), toFree->mChildren.end(),
&SkewBinomialHeap::freeTree);

/* Free the node itself. */
delete toFree;
}

/* Size queries return the cached size. */
template <typename T, typename Comparator>
size_t SkewBinomialHeap<T, Comparator>::size() const {
return mSize;
}

/* Emptiness queries return whether the size is zero. */
template <typename T, typename Comparator>
bool SkewBinomialHeap<T, Comparator>::empty() const {
return size() == 0;
}

/* Adding an element to the tree wraps it up in a singleton, then merges it
* into the tree.
*/

template <typename T, typename Comparator>
void SkewBinomialHeap<T, Comparator>::push(const T& value) {
/* Wrap the object up in a new singleton tree and add it. */
insertSingleton(new Tree(value, 0));

/* Increment our cached copy of the size so we track the number of elements
* correctly.
*/

++mSize;
}

/* Inserting a singleton tree follows the rules specified in the file comments
* to combine the new singleton with the existing trees.
*/

template <typename T, typename Comparator>

/* If the last two trees have the same order, merge them together into one
* tree using a skew merge.
*/

if (mTrees.size() >= 2 && mTrees->mOrder == mTrees->mOrder) {
/* First, remove both trees from the tree list; we're going to be replacing
* them with one new tree.
*/

Tree* first  = mTrees.front(); mTrees.pop_front();
Tree* second = mTrees.front(); mTrees.pop_front();

/* Link the trees using a standard merge. */
Tree* newTree = mergeTrees(first, second);

/* Now, if the singleton tree has a value less than that of the new union,
* swap its value with the value atop the tree.
*/

/* Make the singleton (which might now be holding a value other than the
* one it started with) an entry in the resulting singleton list.
*/

/* Finally, put this tree at the front of the list of trees. */
mTrees.push_front(newTree);
}
/* Otherwise, just prepend the tree to the front of the list; we have nothing
* to merge.
*/

else {
}
}

/* Merging two trees makes the tree with the smaller root the parent of the
* other tree, then increases its order.
*/

template <typename T, typename Comparator>
typename SkewBinomialHeap<T, Comparator>::Tree*
SkewBinomialHeap<T, Comparator>::mergeTrees(Tree* one, Tree* two) {
assert (one && two);

/* Make sure that the first tree has a lower value, and exchange the two if
* that isn't the case so we can pretend it was all along.
*/

if (mComp(two->mValue, one->mValue))
std::swap(one, two);

/* Make two the last child of one. */
one->mChildren.push_back(two);

/* Increase the order of the first tree, since it now has another child. */
++one->mOrder;

/* Hand back this tree as the new root of the merger. */
return one;
}

/* Locating the minimum element works by scanning the trees for the lowest
* value and handing back a reference to it.
*/

template <typename T, typename Comparator>
const T& SkewBinomialHeap<T, Comparator>::top() const {
assert (!empty());
return mTrees[indexOfMin()]->mValue;
}

/* To find the minimum element, we scan the roots of all the trees. */
template <typename T, typename Comparator>
size_t SkewBinomialHeap<T, Comparator>::indexOfMin() const {
/* Guess that the smallest element is in the first tree. */
int min = 0;

/* Update this guess. */
for (size_t i = 1; i < mTrees.size(); ++i)
if (mComp(mTrees[i]->mValue, mTrees[min]->mValue))
min = i;

/* Hand back a reference to the value. */
return min;
}

/* Merge operation forwards the request to a helper function which does the
* actual logic.
*/

template <typename T, typename Comparator>
void SkewBinomialHeap<T, Comparator>::merge(SkewBinomialHeap& other) {
/* Do the actual logic necessary to merge the heaps together. */
mergeHeaps(mTrees, other.mTrees);

/* Update the size information of both trees; this heap just grew in size,
* while the other heap lost all its elements.
*/

mSize += other.mSize;
other.mSize = 0;
}

/* Given two lists of trees, merges them together into a single list of trees
* holding all the original elements.
*/

template <typename T, typename Comparator>
void SkewBinomialHeap<T, Comparator>::mergeHeaps(std::deque<Tree*>& lhs,
std::deque<Tree*>& rhs) {
/* Merge all of the trees from the two input sequences together by their
* length.  We'll use this to simplify the processing logic.
*/

std::deque<Tree*> allTrees;
while (!lhs.empty() && !rhs.empty()) {
if (lhs.front()->mOrder < rhs.front()->mOrder) {
allTrees.push_back(lhs.front()); lhs.pop_front();
} else {
allTrees.push_back(rhs.front()); rhs.pop_front();
}
}

/* Add the remaining heaps to the list as well.  Only one of these two
* branches will execute, so this maintains the sorted order.
*/

allTrees.insert(allTrees.end(), lhs.begin(), lhs.end());
allTrees.insert(allTrees.end(), rhs.begin(), rhs.end());
lhs.clear();  rhs.clear();

/* The merge process is similar to binary addition.  We iterate across the
* trees, at each point looking at all the trees of a certain order.  If
* there's exactly one tree of each size, then we just put that in the output
* list.  If there are two, we put nothing, then store the merge of the tree
* as a "carry."  Finally, if there are three, we store one, then use the
* merge of the other two as a carry.
*
* The difference from regular binary addition that we have to consider is
* that in a skew binomial heap there might be multiple trees of the same
* order.  In the worst case, we'll have four different trees of the same
* order at any one time (since there's at most two trees of the same order
* in each tree).  Consequently, we'll generalize the logic a bit.  For each
* two trees of a given order that we find, we'll merge them together into
* a tree of the next highest-order.  Any odd tree remaining is left in the
* output sequence.
*/

while (!allTrees.empty()) {
/* Populate a buffer with trees that have the same order as the first tree
* left in the worklist.  Initially this just has the first tree.
*/

std::deque<Tree*> ofSameOrder;
ofSameOrder.push_back(allTrees.front()); allTrees.pop_front();

/* Move all other trees into this list with the same order. */
while (!allTrees.empty() &&
allTrees.front()->mOrder == ofSameOrder.front()->mOrder) {
ofSameOrder.push_back(allTrees.front()); allTrees.pop_front();
}

/* If we have an odd number of trees, write one of them to the output. */
if (ofSameOrder.size() % 2 == 1) {
lhs.push_back(ofSameOrder.front()); ofSameOrder.pop_front();
}
assert (ofSameOrder.size() % 2 == 0);

/* Keep merging pairs of remaining trees and putting them back in the
* worklist.
*/

for (size_t i = 0; i < ofSameOrder.size(); i += 2)
allTrees.push_front(mergeTrees(ofSameOrder[i], ofSameOrder[i + 1]));
}
}

/* Removing the min element requires removing it from the list of trees, then
* adding the child trees and singletons back in.
*/

template <typename T, typename Comparator>
void SkewBinomialHeap<T, Comparator>::pop() {
assert (!empty());

/* Track down the index of the smallest tree, then remove it from the
* list of trees.
*/

const size_t minIndex = indexOfMin();
Tree* toRemove = mTrees[minIndex];
mTrees.erase(mTrees.begin() + minIndex);

/* Now, we need to merge all of the child trees back in to the master
* list.
*/

mergeHeaps(mTrees, toRemove->mChildren);

/* For each of the singletons held by this tree, insert that singleton back
* into the tree.
*/

for (size_t i = 0; i < toRemove->mSingletons.size(); ++i)
insertSingleton(toRemove->mSingletons[i]);

/* Decrement the total number of trees remaining here; we're about to remove
* something.
*/

--mSize;

/* Free the memory associated with this entry. */
delete toRemove;
}

/* Cloning a tree recursively copies all of the subtrees. */
template <typename T, typename Comparator>
typename SkewBinomialHeap<T, Comparator>::Tree*
SkewBinomialHeap<T, Comparator>::cloneTree(const Tree* toClone) {
/* The clone of the empty tree is the empty tree. */
if (!toClone) return NULL;

/* Otherwise, clone the tree's value and order. */
Tree* result = new Tree(toClone->mValue, toClone->mOrder);

/* Deep-copy the children and singletons. */
for (size_t i = 0; i < toClone->mChildren.size(); ++i)
result->mChildren.push_back(cloneTree(toClone->mChildren[i]));
for (size_t i = 0; i < toClone->mSingletons.size(); ++i)
result->mSingletons.push_back(cloneTree(toClone->mSingletons[i]));

/* Hand back the copied tree. */
return result;
}

/* To deep-copy a skew binomial heap, we copy each tree and the cached value
* of the number of nodes present.
*/

template <typename T, typename Comparator>
SkewBinomialHeap<T, Comparator>::SkewBinomialHeap(const SkewBinomialHeap& rhs) {
/* Clone all the trees in order. */
for (size_t i = 0; i < rhs.mTrees.size(); ++i)
mTrees.push_back(cloneTree(rhs.mTrees[i]));

/* Copy the size over so we know how many elements are here. */
mSize = rhs.mSize;
mComp = rhs.mComp;
}

/* To exchange two skew binomial heaps, we just swap the trees and size. */
template <typename T, typename Comparator>
void SkewBinomialHeap<T, Comparator>::swap(SkewBinomialHeap& rhs) {
std::swap(mSize, rhs.mSize);
std::swap(mComp, rhs.mComp);
mTrees.swap(rhs.mTrees);
}

/* Assignment implemented with copy-and-swap. */
template <typename T, typename Comparator>
SkewBinomialHeap<T, Comparator>&
SkewBinomialHeap<T, Comparator>::operator= (const SkewBinomialHeap& rhs) {
SkewBinomialHeap copy = rhs;
swap(copy);
return *this;
}

#endif