도구스개발

퀵셀렉트 k번째 원소 계산기

배열과 k를 넣으면 정렬하지 않고 k번째로 작은 수를 찾는 과정을 분할마다 보입니다. 비교 횟수를 끝까지 정렬했을 때와 견주고, 피벗 규칙에 따라 최악의 경우가 어떻게 실재하는지 직접 볼 수 있습니다.

쉼표나 공백으로 나눠 적습니다. 40개까지, 음수·소수도 됩니다.

번째

1이면 최솟값, 9이면 최댓값입니다.

4번째로 작은 수

4

분할을 3번 하며 17번 비교했습니다. 같은 규칙으로 끝까지 정렬했다면 23번 비교해야 합니다.

찾은 값4
비교 횟수17번
교환 횟수7번
훑은 원소 수의 합20개 (원소 9개)
끝까지 정렬했다면23번 비교
최악의 경우 (n(n−1)/2)36번 비교

피벗 규칙을 바꾸면

규칙비교분할
첫 원소175
가운데 원소173
세 값의 중앙값113

같은 배열·같은 k를 세 규칙으로 각각 돌린 결과입니다. 「최악 — 정렬된 배열 + 첫 원소」 예제를 눌러 보면 첫 원소 규칙만 비교 횟수가 n(n−1)/2까지 치솟는 것을 볼 수 있습니다. 피벗이 매번 남은 구간에서 가장 작은 값이라 한쪽이 텅 비고 다른 쪽이 하나씩만 줄기 때문입니다.

단계별로 보기

1. [0, 8] · 피벗 1 · 비교 8번

1
2
9
4
5
8
3
6
7

피벗 1이 1번째 자리에 놓였습니다. 찾는 4번째는 그보다 뒤라 오른쪽 8개만 따라갑니다. 왼쪽 0개는 다시 보지 않습니다.

2. [1, 8] · 피벗 5 · 비교 7번

1
2
4
3
5
8
9
6
7

피벗 5이 5번째 자리에 놓였습니다. 찾는 4번째는 그보다 앞이라 왼쪽 3개만 따라갑니다. 오른쪽 4개는 다시 보지 않습니다.

3. [1, 3] · 피벗 4 · 비교 2번

1
2
3
4
5
8
9
6
7

피벗 4이 4번째 자리에 놓였습니다. 찾던 자리라 여기서 끝납니다.

파랗게 칠한 칸이 제자리에 놓인 피벗이고, 흐린 칸은 다시 보지 않는 구간입니다. 퀵정렬이라면 흐린 쪽도 마저 정렬하지만 퀵셀렉트는 k가 있는 한쪽만 따라 내려갑니다. 이 한 줄 차이가 평균 O(n log n)과 O(n)을 가릅니다.

매번 절반씩 줄어든다고 치면 훑는 양이 n + n/2 + n/4 + … = 2n이라 O(n)이 됩니다. 정렬은 층마다 전부를 다시 훑어야 해서 층이 log n개 쌓여 n log n이 됩니다. 위의 「훑은 원소 수의 합」이 원소 수의 두세 배 안쪽이면 그 계산이 실제로 그렇게 돌고 있다는 뜻입니다.
실제 구현은 피벗을 무작위로 골라 최악의 경우를 확률적으로 피합니다. 여기서는 같은 입력에 같은 과정이 나와야 해서 규칙을 고정했습니다. 「평균이 O(n)」은 언제나 빠르다는 뜻이 아니며, 입력과 피벗 규칙이 맞물리면 O(n²)까지 주저앉을 수 있습니다.

사용 방법

  1. 1배열을 쉼표나 공백으로 나눠 적습니다.
  2. 2k를 넣습니다. 1이면 최솟값, 원소 수와 같으면 최댓값입니다.
  3. 3피벗 규칙을 고릅니다. 첫 원소·가운데 원소·세 값의 중앙값 중 하나입니다.
  4. 4단계별 배열에서 파란 칸(제자리에 놓인 피벗)과 흐린 칸(다시 보지 않는 구간)을 따라갑니다.
  5. 5「최악 — 정렬된 배열 + 첫 원소」 예제를 눌러 비교 횟수가 어디까지 치솟는지 봅니다.

자주 묻는 질문

평균 O(n)으로, 정렬의 O(n log n)보다 한 단계 빠릅니다. 퀵정렬과 분할까지는 똑같지만 양쪽을 모두 정렬하지 않고 k가 있는 한쪽만 따라 내려가기 때문입니다. 매번 절반씩 줄어든다고 치면 훑는 양이 n + n/2 + n/4 + … = 2n이 되고, 정렬은 층마다 전부를 다시 훑어야 해서 층이 log n개 쌓입니다.

최악의 경우 O(n²)입니다. 이미 정렬된 배열에 「첫 원소」 피벗 규칙을 쓰면 피벗이 매번 남은 구간에서 가장 작은 값이라 한쪽이 텅 비고 다른 쪽이 하나씩만 줄어, 비교 횟수가 n(n−1)/2에 이릅니다. 이 계산기의 「최악」 예제에서 그 숫자를 직접 볼 수 있습니다.

실제 구현은 무작위로 고릅니다. 어떤 입력이 오더라도 최악의 경우에 걸릴 확률을 낮출 수 있기 때문입니다. 이 계산기는 같은 입력에 같은 과정이 나와야 해서 첫 원소·가운데 원소·세 값의 중앙값 세 가지로 고정했습니다. 세 값의 중앙값은 실전에서 흔히 쓰는 절충안으로, 정렬된 입력에서도 무너지지 않습니다.

쓸 수 있습니다. 원소가 n개일 때 k를 ⌈n/2⌉로 두면 중앙값이 나옵니다. 짝수 개라면 n/2번째와 n/2+1번째를 각각 찾아 평균을 내면 됩니다. 전체를 정렬해서 가운데를 꺼내는 것보다 평균적으로 빠른 것이 이 알고리즘을 쓰는 가장 흔한 이유입니다.

로무토(Lomuto) 분할입니다. 피벗을 구간 맨 뒤로 보내 놓고 왼쪽부터 훑으며 피벗보다 작은 값을 앞으로 모은 뒤, 마지막에 피벗을 그 경계로 되돌립니다. 호어(Hoare) 분할보다 교환이 잦지만 「지금 어디까지 모았는가」가 한눈에 보여 과정을 따라가기에 낫습니다. 비교 횟수는 구간 길이가 m일 때 정확히 m−1번입니다.

됩니다. k번째로 작은 값은 중복을 따로 세지 않고 「정렬했을 때 k번째 자리에 오는 값」으로 정의합니다. 예를 들어 3, 3, 1에서 2번째로 작은 수는 3입니다. 다만 중복이 아주 많으면 로무토 분할에서 한쪽으로 몰려 단계가 늘어날 수 있습니다.

전송되지 않습니다. 모든 계산은 브라우저 안에서 이뤄지고, 입력값은 이 기기에만 남습니다.

알아두면 좋은 점

  • 검증은 무작위 배열 400벌을 모든 k와 세 피벗 규칙으로 각각 돌려, 정렬해서 k번째를 꺼낸 값과 일치하는지 대조해 했습니다. 중복이 많은 배열과 원소가 하나인 경우도 따로 맞췄습니다.
  • 정렬된 배열 20개에 첫 원소 피벗으로 최댓값을 찾으면 비교 횟수가 정확히 n(n−1)/2 = 190번이 되는 것을 테스트로 고정해 두었습니다. 같은 배열에 가운데 원소 피벗을 쓰면 그 4분의 1 아래로 떨어집니다.
  • 단계마다 분할 뒤 피벗 왼쪽이 모두 작고 오른쪽이 모두 작지 않은지, 단계별 비교·교환의 합이 총계와 맞는지도 무작위 입력으로 확인했습니다.
  • 피벗은 무작위로 고르지 않습니다. 같은 입력에 같은 과정이 나오게 하려는 것이며, 실제 구현은 무작위 피벗을 써서 최악의 경우를 확률적으로 피합니다.
  • 원소 40개까지 다룹니다. 단계마다 배열 전체를 보이는 것이 목적이라 그보다 크면 화면이 읽히지 않습니다.

함께 보면 좋은 도구

마지막 검증: 2026년 9월 1일 · 결과는 참고용 추정치입니다.