// constructor
template <typename Key, typename Element, typename Comp>
PriorityQueue<Key, Element, Comp>::PriorityQueue() {
  T = Tree();
}

// number of elements
template <typename Key, typename Element, typename Comp>
int PriorityQueue<Key, Element, Comp>::size() const {
  return (T.size()-1)/2;
}

// is the queue empty?
template <typename Key, typename Element, typename Comp>
bool PriorityQueue<Key, Element, Comp>::isEmpty() const {
  return (size()==0);
}

// return element with minimum key
template <typename Key, typename Element, typename Comp>
Element& PriorityQueue<Key, Element, Comp>::minElement() throw(EmptyContainerException) {
  if (isEmpty())
    throw EmptyContainerException("Minimum element of empty queue");
  return element(T.root());
}

// return minimum key
template <typename Key, typename Element, typename Comp>
const Key& PriorityQueue<Key, Element, Comp>::minKey() const throw(EmptyContainerException) {
  if (isEmpty())
    throw EmptyContainerException("Minimum key of empty queue");
  return key(T.root());
}



// insert (key,element) into queue
template <typename Key, typename Element, typename Comp>
void PriorityQueue<Key, Element, Comp>::insertItem(const Key& k, const Element& e) {
  Position z = add(Item(k, e));
  while (!T.isRoot(z)) {                                // up-heap bubbling
    Position u = T.parent(z);
    if (comp(key(u), key(z)) <= 0) break;
    T.swapElements(u, z);
    z = u;
  }
}


// remove minimum (element,key) entry
template <typename Key, typename Element, typename Comp>
void PriorityQueue<Key, Element, Comp>::removeMin() throw(EmptyContainerException) {
  if (isEmpty())
    throw EmptyContainerException("Removal from empty queue");
  if (size() == 1) {
    remove();
  } else {
    T.replaceElement(T.root(), remove());
    Position r = T.root();
    while (T.isInternal(T.leftChild(r))) {              // down-heap bubbling
      Position s = T.rightChild(r);
      if (T.isExternal(T.rightChild(r)) || comp(key(T.leftChild(r)), key(T.rightChild(r))) <= 0)
        s = T.leftChild(r);
      if (comp(key(s), key(r)) < 0) {
        T.swapElements(r, s);
        r = s;
      }
      else break;
    }
  }
}


// adds new node and returns position
template <typename Key, typename Element, typename Comp>
typename PriorityQueue<Key, Element, Comp>::Position PriorityQueue<Key, Element, Comp>::add(Item it) {
  Position p = findNode(size()+1);
  T.expandExternal(p);
  T.replaceElement(p,it);
  return p;
}

// remove last internal node and return item
template <typename Key, typename Element, typename Comp>
typename PriorityQueue<Key, Element, Comp>::Item PriorityQueue<Key, Element, Comp>::remove() {
  Position p = findNode(size());
  Item i = p.element();
  T.removeAboveExternal(T.leftChild(p));
  return i;
}


// get last node (even if external)
template <typename Key, typename Element, typename Comp>
typename PriorityQueue<Key, Element, Comp>::Position PriorityQueue<Key, Element, Comp>::findNode(int place) {
  int s, numbits, i;
  s = place;
  numbits = 0;
  while (s) {
    s >>= 1;
    numbits++;
  }
  s = place;

  Position p = T.root();

  for (i=numbits-2; i>=0; i--) {
    if (s & (1<<i))
      p = T.rightChild(p);
    else
      p = T.leftChild(p);
  }

  return p;
}
