Quickselect is an algorithm that finds the -th smallest element in an array of numbers 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 Quicksort 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 .
    • If , the -th smallest element is the -th smallest element among . Solve for it recursively.
    • If , the -th smallest element is the -th smallest element among . Solve for it recursively.
    • Otherwise, the -th smallest element is .

This algorithm solves the problem in expected time and space.

int quickselect(int n, std::vector<int> a, int k) {
	auto l = a.begin(), r = a.end();
	while (true) {
		int x = l[std::uniform_int_distribution<int>(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 (k < s - l) {
			r = s;
		} else if (k >= t - l) {
			k -= t - l;
			l = t;
		} else {
			return x;
		}
	}
}

Algorithm 1

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

  1. Divide into groups of , ignoring the remainder.
  2. Apply an appropriate sorting algorithm (e.g., Selection Sort, Insertion Sort, Bubble Sort, Merge Sort, Heapsort, Quicksort) to find the median of each group.
  3. Find the median of these medians recursively, and set to this median.

This algorithm solves the problem in time and space.

int quickselect(int n, std::vector<int> a, int k) {
	return 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];
	})(a.begin(), a.end(), k);
}