/**
   * extract minimum from the heap.
   *
   * <p>minor differences from Cormen et al. pseudocode are present.
   *
   * @return
   */
  public HeapNode extractMin() {

    int sentinel = DoubleLinkedCircularList.sentinelKey;

    HeapNode z = minimumNode;

    if (z != null) {

      // detach each child and add it to heap
      HeapNode x = z.getChildren().getSentinel().getRight();

      // for each child x of z
      while (x.getKey() != sentinel) {
        HeapNode next = x.getRight();
        rootList.insert(x);
        x = next;
      }

      rootList.remove(z);

      if (z.getRight().getKey() == z.getKey()) {
        minimumNode = null;
      } else {
        minimumNode = z.getRight();
        consolidate();
      }

      n--;
    }

    return z;
  }
  /**
   * a depth first search of all nodes (that is, it descends all children of a node before
   * proceeding to the next in the current doubly linked circular list).
   *
   * @param key
   * @return
   */
  HeapNode search(long key) {

    HeapNode node = rootList.getSentinel().getRight();

    int sentinel = DoubleLinkedCircularList.sentinelKey;

    Stack<HeapNode> stack = new Stack<HeapNode>();

    while (!stack.isEmpty() || (node.getKey() != sentinel)) {
      if (node.getKey() != sentinel) {

        stack.push(node);

        node = node.getRight();

      } else {

        node = stack.pop();

        // System.out.println(node.key);
        if (node.getKey() == key) {
          return node;
        }

        node = node.getChildren().getSentinel().getRight();
      }
    }

    return null;
  }
 /**
  * decrease key for node x
  *
  * <p>runtime is O(1)
  *
  * @param x
  * @param decreaseToThisKey
  */
 public void decreaseKey(HeapNode x, long decreaseToThisKey) {
   if (decreaseToThisKey > x.getKey()) {
     throw new IllegalArgumentException("key cannot be larger than x.key");
   }
   x.setKey(decreaseToThisKey);
   HeapNode y = x.getParent();
   if ((y != null) && (x.getKey() < y.getKey())) {
     cut(x, y);
     cascadingCut(y);
   }
   if (x.getKey() < minimumNode.getKey()) {
     minimumNode = x;
   }
 }
 protected void printRootList() {
   StringBuffer sb = new StringBuffer();
   HeapNode t = this.rootList.getSentinel().getRight();
   while (t.getKey() != DoubleLinkedCircularList.sentinelKey) {
     if ((minimumNode == null) || (t.getKey() < minimumNode.getKey())) {
       minimumNode = t;
     }
     String str = String.format("%d", t.getKey());
     if (sb.length() > 0) {
       sb.append(" ");
     }
     sb.append(str);
     t = t.getRight();
   }
   sb.insert(0, "Looking for " + minimumNode + " :");
   log.info(sb.toString());
 }
  /**
   * insert node into heap. runtime is O(1). makes no attempt to consolidate tree.
   *
   * @param node
   */
  public void insert(HeapNode node) {
    if (node.getKey() == DoubleLinkedCircularList.noValue) {
      throw new IllegalArgumentException("node.key must be set before insert into heap");
    }
    node.setNumberOfChildren(0);
    node.setParent(null);
    node.removeChildren();
    node.setLeft(node);
    node.setRight(node);
    node.setMark(false);

    // concatenate root list containing node with this.rootList
    rootList.insert(node);

    if ((minimumNode == null) || (node.getKey() < minimumNode.getKey())) {
      minimumNode = node;
    }

    n++;
  }
  void consolidate() {

    // D[n] = max degree of any node = lg_2(n) = lg_2(Integer.MAX) = 31
    // int maxDegree = (int) (Math.log(this.n)/Math.log(2));
    int maxDegree = 31;

    HeapNode[] a = new HeapNode[maxDegree];

    HeapNode w = rootList.getSentinel().getRight();

    // n*m*(constants)
    while (w.getKey() != DoubleLinkedCircularList.sentinelKey) {

      HeapNode x = w;

      // because the x.right gets changed in link(), nab the next
      // reference before link
      HeapNode next = w.getRight();

      int d = x.getNumberOfChildren();

      // is there another node of the same degree, that is, has the
      // same number of children?
      while ((d < a.length) && (a[d] != null)) {

        HeapNode y = a[d];

        if (x.getKey() > y.getKey()) {
          HeapNode tmp = x;
          x = y;
          y = tmp;
        }

        // link removes y (which has a key larger than x now) from
        // rootList and adds it as a child of x
        link(y, x);

        a[d] = null;
        d++;
      }
      if (d < a.length) {
        a[d] = x;
      } else {
        throw new IllegalStateException("maxDegree=" + maxDegree + " but d is " + d);
      }

      w = next;
    }

    minimumNode = null;

    for (int i = 0; i < a.length; i++) {
      if (a[i] != null) {

        rootList.remove(a[i]);
        rootList.insert(a[i]);

        // not changing the minimumNode because the rootList content
        // has not changed, so the minimum in that has not changed
        if ((minimumNode == null) || (a[i].getKey() < minimumNode.getKey())) {
          minimumNode = a[i];
        }
      }
    }
  }