Quicksort is an algorithm that sorts an array of numbers in non-decreasing order in time and space.

Tip

This problem can also be solved by Selection Sort in time and space.

Tip

This problem can also be solved by Insertion Sort in time and space.

Tip

This problem can also be solved by Bubble Sort in time and space.

Tip

This problem can also be solved by Merge Sort in time and space.

Tip

This problem can also be solved by Heapsort in time and space.

Tip

This problem can also be solved by Quickselect in time and space.

Algorithm 0

  1. Let be a number chosen uniformly at random from .
  2. Let be the numbers among that are less than , be the numbers equal to , be the numbers greater than .
  3. Sort and recursively.
  4. is the result of sorting .

This algorithm solves the problem in expected time and space.

void quicksort(int n, std::vector<int> &a) {
	y_combinator([&](auto &&self, std::vector<int>::iterator l, std::vector<int>::iterator r) -> void {
		if (l == r) {
			return;
		}
 
		int x = l[std::uniform_int_distribution<>(0, r - l - 1)(rng)];
 
		auto s = l, t = r;
		for (auto i = s; i != t; ) {
			if (*i < x) {
				std::swap(*i++, *s++);
			} else if (*i > x) {
				std::swap(*i, *--t);
			} else {
				i++;
			}
		}
		self(l, s), self(t, r);
	})(a.begin(), a.end());
}

Algorithm 1

Based on Algorithm 0, instead of sorting both subarrays recursively, sorting the shorter one recursively and the longer one iteratively yields an algorithm that solves the problem in expected time and space.

void quicksort(int n, std::vector<int> &a) {
	y_combinator([&](auto &&self, std::vector<int>::iterator l, std::vector<int>::iterator r) -> void {
		while (l != r) {
			int x = l[std::uniform_int_distribution<>(0, r - l - 1)(rng)];
 
			auto s = l, t = r;
			for (auto i = s; i != t; ) {
				if (*i < x) {
					std::swap(*i++, *s++);
				} else if (*i > x) {
					std::swap(*i, *--t);
				} else {
					i++;
				}
			}
 
			if (s - l < r - t) {
				self(l, s);
				l = t;
			} else {
				self(t, r);
				r = s;
			}
		}
	})(a.begin(), a.end());
}

Algorithm 2

Based on Algorithm 0, instead of choosing at random, determine in the following way:

  • Apply Quickselect to find the median of , and set to this median.

This algorithm solves the problem in time and space.

void quicksort(int n, std::vector<int> &a) {
	auto quickselect = y_combinator([&](auto &&self, std::vector<int>::iterator l, std::vector<int>::iterator r, int k) -> int {
		while (r - l >= 5) {
			for (int i = 0; i < (r - l) / 5; i++) {
				std::sort(l + 5 * i, l + 5 * (i + 1));
				std::swap(l[i], l[5 * i + 2]);
			}
 
			int x = self(l, l + (r - l) / 5, (r - l) / 10);
 
			auto s = l, t = r;
			for (auto i = s; i != t; ) {
				if (*i < x) {
					std::swap(*i++, *s++);
				} else if (*i > x) {
					std::swap(*i, *--t);
				} else {
					i++;
				}
			}
 
			if (k < s - l) {
				r = s;
			} else if (k >= t - l) {
				k -= t - l;
				l = t;
			} else {
				return x;
			}
		}
 
		std::sort(l, r);
		return l[k];
	});
 
	y_combinator([&](auto &&self, std::vector<int>::iterator l, std::vector<int>::iterator r) -> void {
		if (l == r) {
			return;
		}
 
		int x = quickselect(l, r, (r - l) / 2);
		self(l, std::lower_bound(l, r, x));
		self(std::upper_bound(l, r, x), r);
	})(a.begin(), a.end());
}