Home Manual Reference Source

src/consolidate.js

import {_append as list_insert} from '@data-structure-algebra/circularly-linked-list';
import link from './link.js';

/**
 * CONSOLIDATE: Consolidate the root list of a heap.
 *
 * The next step, in which we reduce the number of trees in the Fibonacci heap,
 * is consolidating the root list of H, which the call CONSOLIDATE(H)
 * accomplishes. Consolidating the root list consists of repeatedly executing
 * the following steps until every root in the root list has a distinct degree
 * value:
 *
 *   1. Find two roots x and y in the root list with the same degree. Without
 *   loss of generality, let x.key <= y.key.
 *
 *   2. Link y to x: remove y from the root list, and make y a child of x by
 *   calling the FIB-HEAP-LINK procedure. This procedure increments the
 *   attribute x:degree and clears the mark on y.
 *
 * The procedure CONSOLIDATE uses an auxiliary array A[0..D(H.n)] to
 * keep track of roots according to their degrees. If A[i] = y, then y is
 * currently a root with y.degree = i. Of course, in order to allocate the
 * array we have to know how to calculate the upper bound D(H.n) on the maximum
 * degree, but we will see how to do so in Section 19.4.
 *
 * @param compare Comparison function.
 * @param l Root list.
 */
export default function consolidate(compare, l) {
	const A = [];

	let next = l;

	do {
		let x = next;
		next = x.next;
		let d = x.degree;

		let n = d - A.length;
		if (n >= 0) {
			while (n-- > 0) A.push(null);
			A.push(x);
		} else {
			while (A[d] !== null) {
				let y = A[d]; // Another node with the same degree as x
				if (compare(y.value, x.value) < 0) {
					// CANNOT EXCHANGE VALUES BECAUSE THAT WOULD INVALIDATE
					// EXISTING POINTERS
					y = x;
					x = A[d];
				}

				link(y, x);
				A[d] = null; // Put before link if using x.degree ?
				++d;
				if (d === A.length) {
					A.push(null);
					break;
				}
			}

			A[d] = x;
		}
	} while (next !== l);

	let min = null;

	for (const x of A) {
		if (x === null) continue;
		if (min === null) {
			// Create a root list for H containing just A[i]
			x.next = x;
			x.prev = x;
			min = x;
		} else {
			// Insert A[i] into H's root list
			list_insert(min, x);
			// Update minimum if necessary
			if (compare(x.value, min.value) < 0) min = x;
		}
	}

	return min;
}