정렬

선택 정렬

가장 작은 것부터 꺼내 놓기

카드 여섯 장을 작은 수부터 왼쪽에 늘어놓아 보세요. 한 장씩 보며 가장 작은 카드를 찾아 왼쪽 끝으로 보냅니다.

카드 여섯 장을 작은 수부터 왼쪽에 늘어놓습니다. 먼저 맞혀 보세요. 첫 바퀴를 끝내면 맨 앞에 어떤 카드가 올까요?

5
2
9
1
7
4
견줘 본 횟수 0 · 바꾼 횟수 0

카드를 정렬하는 데 0번 견주고 0번 바꿨습니다.

5 → 2 → 1첫 바퀴에서 가장 작은 카드 후보가 이렇게 바뀌었습니다.

버블 정렬 · 바꾼 횟수8번
선택 정렬 · 바꾼 횟수2번
같은 카드를 정렬합니다. 견준 횟수는 둘 다 15번입니다. 선택 정렬은 많아야 5번만 바꿉니다.

한 바퀴에 가장 작은 카드 하나를 골라 맨 앞 빈 칸과 맞바꾸는 방법 = 선택 정렬

이미 정렬돼 있어도 훑는 횟수는 같다

  • 바퀴마다 — 남은 카드를 끝까지 봐야 가장 작은 카드를 안다. 앞에서 찾아도 끝까지 본다
  • 훑는 횟수 — 5 + 4 + 3 + 2 + 1 = 15번. 카드가 n장이면 n(n−1)/2번이다
  • 정렬된 카드도 — 맨 앞이 가장 작은지 끝까지 봐야 안다. 위의 「이미 정렬된 카드로 해 보기」로 세어 보면 여전히 15번이다

코드는 후보 하나를 들고 훑는 것이 전부다

다음을 눌러 한 줄씩 넘기며 후보가 바뀌는 걸 보세요. 앞에서부터 확정된 칸이 쌓입니다.

다음을 눌러 한 줄씩 넘겨 보세요

n = 6

selection_sort.py
  1. 1def selection_sort(arr):
  2. 2 n = len(arr)
  3. 3 for i in range(n - 1):
  4. 4 min_idx = i
  5. 5 for j in range(i + 1, n):
  6. 6 if arr[j] < arr[min_idx]:
  7. 7 min_idx = j
  8. 8 arr[i], arr[min_idx] = arr[min_idx], arr[i]
  9. 9 return arr
0 / 37
  • i — 지금 채우는 칸. 앞 i칸은 이미 자리를 잡았다
  • min_idx — 지금까지 본 카드 중 가장 작은 카드의 칸 번호(후보)
  • j — 지금 견주는 칸. i + 1 부터 끝까지 간다

거꾸로 선 카드 6 5 4 3 2 1 을 선택 정렬하면 자리를 몇 번 바꿀까요?

선택 정렬에서 틀리는 자리

  • 같은 값의 순서가 뒤집힌다 — 먼 칸과 맞바꾼다. 2a 2b 1c 를 정렬하면 1c 2b 2a 가 된다. 안정 정렬이 아니다
  • < 대신 <= — 같은 값 중 뒤쪽을 후보로 잡는다. 이미 정렬된 1a 1b 2c 가 1b 1a 2c 로 바뀐다
  • range(i + 1, n) 대신 range(i, n) — 자기 자신과도 견줘 비교가 15번에서 20번으로 는다. 답은 그대로 맞다

쓸 일은 적지만 이럴 때 나온다

n 이 작다바꾸는(쓰는) 횟수를 줄여야 한다k 번째로 작은 것까지만 필요하다

실전에서 정렬이 필요할 때는 sorted() 한 줄이면 됩니다.

다음 장에서는 카드를 한 장씩 알맞은 자리에 끼워 넣는 삽입 정렬을 봅니다.