๐ Python์ sort()์ ํ์ํธ(Timsort) ์ ๋ฆฌ
๐ฏ ์ ๋ ฌ(Sort)์ด๋?
์ ๋ ฌ์ ๋ฐ์ดํฐ๋ฅผ ์ผ์ ํ ์์(์ค๋ฆ์ฐจ์, ๋ด๋ฆผ์ฐจ์ ๋ฑ)๋ก ๋์ดํ๋ ์์
์
๋๋ค.
์ ๋ ฌ๋ ๋ฐ์ดํฐ๋ ์ด์ง ํ์ ๋ฑ ํจ์จ์ ์ธ ์๊ณ ๋ฆฌ์ฆ ํ์ฉ์ด ๊ฐ๋ฅํด์ง๋ฏ๋ก, ์ปดํจํฐ ๊ณผํ์์ ๋งค์ฐ ์ค์ํ ๋ฌธ์ ์
๋๋ค.
โ๏ธ ์ ๋ ฌ์ ์์ ์ฑ (Stability)
- ์์ ์ ๋ ฌ (Stable Sort) ๐ข
- ๋์ผํ ๊ฐ์ ๊ฐ์ง ๋ฐ์ดํฐ์ ์๋ ์ ๋ ฅ ์์๊ฐ ์ ์ง๋๋ ์ ๋ ฌ
- (์: ๋ณํฉ์ ๋ ฌ, ๋ฒ๋ธ์ ๋ ฌ, ์ฝ์ ์ ๋ ฌ)
- ๋ถ์์ ์ ๋ ฌ (Unstable Sort) ๐ด
- ๋์ผํ ๊ฐ์ ์ ๋ ฅ ์์๊ฐ ๋ณด์ฅ๋์ง ์๋ ์ ๋ ฌ
- (์: ํต์ ๋ ฌ, ํ์ ๋ ฌ, ์ ํ์ ๋ ฌ)
๐ ์ฃผ์ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ ์์ฝ
์ ๋ ฌ ๋ฐฉ์ | ์๊ฐ๋ณต์ก๋(ํ๊ท ) | ์์ ์ฑ | ํน์ง ๋ฐ ์ค๋ช |
---|---|---|---|
๋ฒ๋ธ ์ ๋ ฌ |
O(nยฒ) | ๐ข ์์ | ์ธ์ ํ ์์๋ฅผ ๋ฐ๋ณต ๋น๊ต ๋ฐ ๊ตํ |
์ ํ ์ ๋ ฌ |
O(nยฒ) | ๐ด ๋ถ์์ | ์ต์๊ฐ(๋๋ ์ต๋๊ฐ) ์ ํ ํ ๊ตํ |
์ฝ์
์ ๋ ฌ |
O(nยฒ) | ๐ข ์์ | ์ด๋ฏธ ์ ๋ ฌ๋ ๋ถ๋ถ์ ์ฝ์ |
๋ณํฉ ์ ๋ ฌ |
O(n log n) | ๐ข ์์ | ๋ถํ ์ ๋ณต, ์ถ๊ฐ ๋ฉ๋ชจ๋ฆฌ ํ์ |
ํ ์ ๋ ฌ |
O(n log n) | ๐ด ๋ถ์์ | ํ ์๋ฃ๊ตฌ์กฐ ์ฌ์ฉ, ์ ์๋ฆฌ ์ ๋ ฌ |
ํต ์ ๋ ฌ |
O(n log n) | ๐ด ๋ถ์์ | ํผ๋ฒ ๊ธฐ์ค ๋ถํ , ํ๊ท ์ ์ผ๋ก ๋น ๋ฆ |
๐ ํ์ด์ฌ์ ๊ธฐ๋ณธ ์ ๋ ฌ: ํ์ํธ(Timsort)
ํ์ด์ฌ์ list.sort()
์ sorted()
ํจ์๋ ํ์ํธ(Timsort)๋ผ๋ ํ์ด๋ธ๋ฆฌ๋ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํฉ๋๋ค.
๐ค ํ์ํธ(Timsort)๋?
- Tim Peters๊ฐ 2002๋ ํ์ด์ฌ์ ์ํด ์ค๊ณํ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ
- ๋ณํฉ์ ๋ ฌ(Merge Sort)๊ณผ ์ฝ์ ์ ๋ ฌ(Insertion Sort)๋ฅผ ๊ฒฐํฉํ ํ์ด๋ธ๋ฆฌ๋ ๋ฐฉ์
- ์ค์ ๋ฐ์ดํฐ๊ฐ ๋ถ๋ถ์ ์ผ๋ก ์ด๋ฏธ ์ ๋ ฌ๋์ด ์๋ ๊ฒฝ์ฐ ๋งค์ฐ ๋น ๋ฅธ ์ฑ๋ฅ์ ๋ณด์
- ํ์ด์ฌ, Java SE 7, Android, Swift ๋ฑ ๋ค์ํ ์ธ์ด์์ ํ์ค ์ ๋ ฌ๋ก ์ฑํ
โ๏ธ ๋์ ์๋ฆฌ
- ๋ฐ(Run) ๋ถํ
- ์
๋ ฅ ๋ฐ์ดํฐ๋ฅผ ์ต์ run ํฌ๊ธฐ(min_run, ๋ณดํต 32 ๋๋ 64)๋ก ์๋ผ
๊ฐ ๊ตฌ๊ฐ(run)์ด ์ด๋ฏธ ์ ๋ ฌ๋์ด ์๊ฑฐ๋,
์ฝ์ ์ ๋ ฌ๋ก ๋น ๋ฅด๊ฒ ์ ๋ ฌ๋ ์ ์๋๋ก ํจ[2][3][4][5][7].
- ์
๋ ฅ ๋ฐ์ดํฐ๋ฅผ ์ต์ run ํฌ๊ธฐ(min_run, ๋ณดํต 32 ๋๋ 64)๋ก ์๋ผ
- ๋ฐ ๋ณํฉ
- ์ ๋ ฌ๋ run๋ค์ ๋ณํฉ์ ๋ ฌ ๋ฐฉ์์ผ๋ก ํฉ์นจ
- ๋ณํฉ ์, ์คํ์ ์์ธ run์ ํฌ๊ธฐ ๋น์จ์ ์กฐ์ ํด
๊ท ํ์กํ ๋ณํฉ๊ณผ ์์ ์ฑ์ ํ๋ณด[3][4].
- ๊ฐค๋กํ(Galloping) ๋ชจ๋
- ๋ณํฉ ๊ณผ์ ์์ ํ run์ ๊ฐ์ด ์ฐ์์ ์ผ๋ก ์ ํ๋๋ ๊ฒฝ์ฐ,
์ด์ง ํ์์ ํ์ฉํด ๋๋์ ๋ฐ์ดํฐ๋ฅผ ํ ๋ฒ์ ๋ณํฉํ์ฌ ํจ์จ์ ๋์[3][4].
- ๋ณํฉ ๊ณผ์ ์์ ํ run์ ๊ฐ์ด ์ฐ์์ ์ผ๋ก ์ ํ๋๋ ๊ฒฝ์ฐ,
โจ ํ์ํธ์ ์ฃผ์ ํน์ง
- ์์ ์ ๋ ฌ: ๋์ผํ ๊ฐ์ ์ ๋ ฅ ์์๊ฐ ๋ณด์กด๋จ
- ์ต์ /ํ๊ท ์๊ฐ๋ณต์ก๋: O(n log n)
- ๋ถ๋ถ์ ์ผ๋ก ์ ๋ ฌ๋ ๋ฐ์ดํฐ์์ ๋งค์ฐ ๋น ๋ฆ
- ์ค์ ๋ฐ์ดํฐ์ ํจํด(์์ฐ์ค๋ฌ์ด ์ ๋ ฌ ๊ตฌ๊ฐ)์ ์ต๋ํ ํ์ฉ
๐ ํ์ํธ์ ํต์ฌ ์ต์ ํ
- Run ํ์ง ๋ฐ ํ์ฅ: ์ด๋ฏธ ์ ๋ ฌ๋ ๊ตฌ๊ฐ(run)์ ์๋์ผ๋ก ์ธ์,
run์ ๊ธธ์ด๊ฐ min_run๋ณด๋ค ์งง์ผ๋ฉด ์ฝ์ ์ ๋ ฌ๋ก ํ์ฅ[2][3][4][7]. - ์คํ ๊ธฐ๋ฐ ๋ณํฉ ๊ท์น:
๋ณํฉํ run์ ํฌ๊ธฐ ๋น์จ์ ์๊ฒฉํ ๊ด๋ฆฌํด
๋ณํฉ ํ์๋ฅผ ์ต์ํํ๊ณ , ๋ฉ๋ชจ๋ฆฌ ์บ์ ํจ์จ์ ๋์[3]. - ๊ฐค๋กํ(Galloping) ๊ธฐ๋ฒ:
ํ์ชฝ run์์ ์ฐ์์ ์ผ๋ก ๋ง์ ๊ฐ์ด ์ ํ๋๋ฉด,
์ด์ง ํ์์ผ๋ก ๋ณํฉ ์๋๋ฅผ ๊ฐ์ํ[3][4].
๐ ํ์ํธ์ ๋์ ์์ (๊ฐ๋จ ์์ฝ)
- ๋ฆฌ์คํธ๋ฅผ
min_run
ํฌ๊ธฐ๋ก ๋ถํ - ๊ฐ run์ ์ฝ์ ์ ๋ ฌ๋ก ์ ๋ ฌ
- ์ธ์ ํ run๋ค์ ๋ณํฉ์ ๋ ฌ ๋ฐฉ์์ผ๋ก ํฉ์นจ
- ๋ชจ๋ run์ด ํ๋๋ก ํฉ์ณ์ง ๋๊น์ง ๋ฐ๋ณต
๐ป ํ์ด์ฌ์์ ํ์ํธ ์ฌ์ฉ ์์
numbers = [5, 3, 8, 6, 2]
numbers.sort() # ๋ด๋ถ์ ์ผ๋ก ํ์ํธ ์ฌ์ฉ
print(numbers) # [2, 3, 5, 6, 8]
๐ ์ฐธ๊ณ : ํ์ํธ ๊ตฌํ์ ํต์ฌ ์ฝ๋ ๊ตฌ์กฐ (์์ฌ์ฝ๋)
def timsort(arr):
min_run = 32
n = len(arr)
# 1. ๊ฐ run๋ง๋ค ์ฝ์
์ ๋ ฌ ์ํ
for start in range(0, n, min_run):
end = min(start + min_run - 1, n - 1)
insertion_sort(arr, start, end)
# 2. run ๋ณํฉ (๋ณํฉ์ ๋ ฌ ๋ฐฉ์)
size = min_run
while size < n:
for left in range(0, n, 2 * size):
mid = min(n - 1, left + size - 1)
right = min((left + 2 * size - 1), (n - 1))
merge(arr, left, mid, right)
size *= 2
โ ๏ธ ์ค์ ๊ตฌํ์ ํจ์ฌ ๋ณต์กํ๋ฉฐ, run์ ํ์ง, ์คํ ๊ด๋ฆฌ, galloping ๋ฑ ๋ค์ํ ์ต์ ํ๊ฐ ์ ์ฉ๋จ
๐ ์ฐธ๊ณ ์๋ฃ
- [Wikipedia: Timsort][3]
- [GeeksforGeeks: Tim Sort in Python][2]
- [Real Python: Sorting Algorithms in Python][5]
- [skerritt.blog: Timsort โ the fastest sorting algorithm youโve never heard of][4]