21 January 2014

Fork me on GitHub

TODO: This lecture requires substantial work.

Fibonacci Heap

A fib heap is a variable degree tree with heap ordering on keys. It adjusts degree of trees in a graph on the fly. Each parent can have multiple children, but only pointers to the first and last are stored. The children are arranged in a double linked list with pointers to siblings. Fib heaps have a \underline{set} of connectivity trees; the fib heap data structure is an array of trees where each element is a root in a connectivity tree.

Notation

At a node \( x \)

  • pointer parent: \( p(x) \)
  • sibling pointers: \( ls(x), rs(x) \)
  • first and last child pointer: \( fc(x), lc(x) \)
  • key: \( key(x) \)
  • degree (# of children): \( d(x) \)
  • mark: \( m(x) \), boolean value
  • other fields: e.g. node names

Potential function

We use the idea of amortized analysis from last lecture and define the potential function as \[ \phi := \alpha N_F + \beta N_M \] where \( N_F \) is the number of filled positions in the array and \( N_M \) is the number of marked nodes.

Amortized cost is total cost plus a difference in the potential function: \[ A_{op_i} = T_{op_i} + (\phi_i - \phi_{i-1}). \]

Operations on Fib Heap

Decreasing key

Decreasing the key of a node is easier than in a min heap because we are able to move the node out of its current tree and move it to a place in the array. Thus, decreasing the key does not affect any other nodes.

// Pseudocode for decreaseKey(u).
def decreaseKey(u):
  Snip u out of current tree.
  if (p(u) is marked):
    // Cascade moving marked nodes to top.
    Recursively move p(u) to top.
  if (p(u) is not marked):
    Mark p(u).
  Move u to array at index d(u).
  Make larger key child of smaller key.
  Increase degree of smaller key by one.
  Move merged tree into next location.
  Unmark nodes at top.

Time cost for decreasing key

\[ A_{DK} = c_2 + c_3 N_{CM} + (c_1 + c) N_M - \beta N_M + \beta = c_2 \] Where \( N_{CM} \) is the number of consecutive marks along path to root. Pick \( \beta = c_3 + (c_1 + c) \). The last \( \beta \) addition is for marking the root. Total time for decreasing keys is constant \( O(1) \).

Moving and Cascade Merging

We only move nodes if it is marked (see below) and the node, \( u \), is moved into the array position that corresponds to the degree of \( u \). If there are multiple roots that have the same degree then merge. The merged tree will have a larger degree and be moved to a new corresponding position in the array. This leads to "cascading merges".

Marking nodes

When nodes are moved to the top, we unmark it. If a node is marked, merge its parent (recursively) . If a node is un-marked, mark it.

Time cost for cascading merges

Pick \( \alpha = c \) to get constant amortized time. Since merging doesn't change the number of marks, don't care about setting \( \beta \). \[ A_{CM} = c N_M + c_1 - \alpha (N_M - 1) = c_1 + \alpha \in O(1). \]

Delete minimum

Delete the minimum and insert a child into the array with cascading merges, with \( O(1) \) cost for each merge. Total time complexity is \( O(deg(u)) \).

Why called Fibonacci heap?

Lemma: If top node of tree \( T \) has degree \( d \), then \( size(T) \) is at least \( fib_{d-1} \).

We want to show that degree of \( T \) is small as a function of number of vertices, \( n \). The size of the tree is exponentially large as a function of \( d \) at the top.