Home Manual Reference Source

src/partition/yaroslavskiy.js

import assert from 'assert';

/**
 * See http://cs.stackexchange.com/a/24099/20711
 *
 * @param {Function} compare
 * @param {Array} a
 * @param {number} i
 * @param {number} j
 * @return {[number, number]}
 */
const yaroslavskiy = (compare, a, i, j) => {
	assert(i < j);
	--j;

	// Choose outermost elements as pivots
	if (compare(a[i], a[j]) > 0) {
		const t = a[i];
		a[i] = a[j];
		a[j] = t;
	}

	const p = a[i];
	const q = a[j];

	// Partition a according to invariant below
	let l = i + 1;
	let g = j - 1;
	let k = l;

	while (k <= g) {
		if (compare(p, a[k]) > 0) {
			const t = a[k];
			a[k] = a[l];
			a[l] = t;

			++l;
		} else if (compare(q, a[k]) <= 0) {
			while (compare(a[g], q) > 0 && k < g) {
				--g;
			}

			const t = a[k];
			a[k] = a[g];
			a[g] = t;
			--g;

			if (compare(p, a[k]) > 0) {
				const t = a[k];
				a[k] = a[l];
				a[l] = t;
				++l;
			}
		}

		++k;
	}

	--l;
	++g;

	// Swap pivots to final place

	const t1 = a[i];
	a[i] = a[l];
	a[l] = t1;

	const t2 = a[j];
	a[j] = a[g];
	a[g] = t2;

	return [l, g];
};

export default yaroslavskiy;