2024. 1. 16. 23:01ใCS - Roadmap.sh/3. Common Algorithms
CS - 3. Common Algorithms - 3.1. Sorting - 3.1.5 Quick Sort
๐กQuick Sort is a divide and conquer algorithm. It picks an element as pivot and partitions the given array around the picked pivot. There are many different versions of quickSort that pick pivot in different ways.
ํต ์ ๋ ฌ์ ๋ถํ ๋ฐ ์ ๋ณต ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. ์ด ์๊ณ ๋ฆฌ์ฆ์ ์์๋ฅผ ํผ๋ฒ์ผ๋ก ์ ํํ๊ณ ์ ํ๋ ํผ๋ฒ์ ์ค์ฌ์ผ๋ก ์ฃผ์ด์ง ๋ฐฐ์ด์ ๋ถํ ํฉ๋๋ค. ๋ค์ํ ๋ฐฉ์์ผ๋ก ํผ๋ฒ์ ์ ํํ๋ ์ฌ๋ฌ ๊ฐ์ง ๋ฒ์ ์ ํต ์ ๋ ฌ์ด ์์ต๋๋ค.
ํต์ ๋ ฌ(Quick Sort)๋ ๋ถํ ์ ๋ณต(Divide and Conquer) ๋ฐฉ์์ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค.
์ด ๋ฐฉ๋ฒ์ ์ฃผ์ด์ง ๋ฐฐ์ด์ ๋๊ฐ์ ๋ถ๋ถ ๋ฐฐ์ด๋ก ๋ถํ ํ๊ณ , ๊ฐ๊ฐ์ ๋ณ๋๋ก ์ ๋ ฌํ๋ ๋ฐฉ์์ผ๋ก ์๋ํฉ๋๋ค.
ํต ์ ๋ ฌ์ ๋์ ๊ณผ์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
1. ๋ฐฐ์ด์์ ํ๋์ ์์๋ฅผ ๊ณ ๋ฆ ๋๋ค. ์ด๋ฅผ ํผ๋ด(pivot)์ด๋ผ ํฉ๋๋ค.
2. ํผ๋ด๋ณด๋ค ์์ ์์๋ค์ ํผ๋ด์ ์ผ์ชฝ์ผ๋ก, ํฐ ์์๋ค์ ์ค๋ฅธ์ชฝ์ผ๋ก ์ด๋์ํต๋๋ค.
์ด๋ฅผ ๋ถํ (partition)์ด๋ผ๊ณ ํฉ๋๋ค.
3. ๋ถํ ๋ ๋ ๊ฐ์ ์์ ๋ฐฐ์ด์ ๋ํด ์ฌ๊ท์ ์ผ๋ก ์ด ๊ณผ์ ์ ๋ฐ๋ณตํฉ๋๋ค.
In Python
ํ์ด์ฌ์์ ํต์ ๋ ฌ์ ๊ตฌํํด ๋ณด๊ฒ ์ต๋๋ค.
def quick_sort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
less = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
greater = [x for x in arr if x > pivot]
return quick_sort(less) + middle + quick_sort(greater)
ํต ์ ๋ ฌ์ ํ๊ท ์ ์ผ๋ก O(log n) ์ ์๊ฐ ๋ณต์ก๋๋ฅผ ๊ฐ์ง๋๋ค.
๊ทธ๋ฌ๋ ์ต์ ์ ๊ฒฝ์ฐ (์ด๋ฏธ ์ ๋ ฌ๋ ๋ฐฐ์ด ๋ฑ) ์๋ O(n^2)์ ์๊ฐ ๋ณต์ก๋๋ฅผ ๊ฐ์ง ์ ์์ต๋๋ค.
์ ๋ฆฌ & ํ์ฉ
ํต ์ ๋ ฌ์ ๋๋ถ๋ถ์ ๊ฒฝ์ฐ์ ๋งค์ฐ ํจ์จ์ ์ด๋ฉฐ, ์์ ๋ฐฐ์ด์ ๋ํด์๋ ๋น ๋ฅด๊ฒ ๋์ํ๋ฏ๋ก ๋ค๋ฅธ ์๊ณ ๋ฆฌ์ฆ๊ณผ ๊ฒฐํฉํ์ฌ ์ฌ์ฉํ๊ธฐ๋ ํฉ๋๋ค.
์ฃผ์ํ ์ ์, ํผ๋ด ์ ํ์ ๋ฐ๋ผ ์ฑ๋ฅ์ด ํฌ๊ฒ ๋ฌ๋ผ์ง ์ ์์ต๋๋ค.
์ผ๋ฐ์ ์ผ๋ก ์ค๊ฐ๊ฐ์ ํผ๋ด์ผ๋ก ์ ํํ๋ฉด ํจ์จ์ ์ ๋๋ค.
๋, ํต ์ ๋ ฌ์ ์ถ๊ฐ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ฑฐ์ ์ฌ์ฉํ์ง ์๋๋ค๋ ์ฅ์ ์ด ์์ต๋๋ค.
์ด๋ ์ ๋ ฌํ๋ ค๋ ๋ฐ์ดํฐ๊ฐ ๋งค์ฐ ํฐ ๊ฒฝ์ฐ์ ์ ๋ฆฌํฉ๋๋ค.
๋ฐ๋ผ์ ํต์ ๋ ฌ์ ์ผ๋ฐ์ ์ธ ๋ชฉ์ ์ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ์์ฃผ ์ฌ์ฉ ๋๋ฉฐ,
ํนํ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์ ํ์ ์ธ ์ํฉ์์ ์ ์ฉํ๊ฒ ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
Appendix, ํต ์ ๋ ฌ์ ์ ์ถ๊ฐ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ฑฐ์ ์ฌ์ฉํ์ง ์์๊น? (+ in Python)
ํต ์ ๋ ฌ์ด ์ถ๊ฐ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ฑฐ์ ์ฌ์ฉํ์ง ์๋ ์ด์ ๋ ์ด ์๊ณ ๋ฆฌ์ฆ์ด '์ ์๋ฆฌ ์ ๋ ฌ(in-place sort)' ์๊ณ ๋ฆฌ์ฆ ์ด๊ธฐ ๋๋ฌธ์ ๋๋ค.
์ ์๋ฆฌ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ ์ ๋ ฅ ๋ฐฐ์ด ์์ฒด๋ฅผ ์ ๋ ฌํ์ฌ ์ ๋ ฌ๋ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ฉฐ, ์ด ๊ณผ์ ์์ ์ถ๊ณผ์ ์ธ ์ ์ฅ ๊ณต๊ฐ์ ํผ๋ฃก๋ก ํ์ง ์์ต๋๋ค.
ํต ์ ๋ ฌ์์๋ ํผ๋ฒ(pivot)์ ์ ํํ๊ณ , ํผ ๋ฒ์ ๊ธฐ์ค์ผ๋ก ๋ฐฐ์ด์ ๋ ๊ฐ์ ๋ถ๋ถ ๋ฐฐ์ด๋ก ๋ถํ ํ๋ ๊ณผ์ ์ด ์งํ๋ฉ๋๋ค.
์ด ๋ถํ ๊ณผ์ ์ ์๋์ ๋ฐฐ์ด ๋ด์์ ์งํ๋๋ฉฐ, ์๋ก์ด ๋ฐฐ์ด์ ์์ฑํ์ง ์์ต๋๋ค.
๋ถํ ์ด ์งํ๋ ํ์๋ ๊ฐ ๋ถ๋ถ ๋ฐฐ์ด์ ๋ํด ๋์ผํ ๊ณผ์ ์ ์ฌ๊ท์ ์ผ๋ก ๋ฐ๋ณตํ์ฌ ์ ๋ ฌ์ ์์ฑํฉ๋๋ค.
์ด๋ ๊ฒ ์๋์ ๋ฐฐ์ด ๋ด์์ ์ง์ ์์๋ค์ ์์น๋ฅผ ์ ๋ ฌํ๊ธฐ ๋๋ฌธ์,
ํต ์ ๋ ฌ์ ์ถ๊ฐ์ ์ธ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ฑฐ์ ํ์๋ก ํ์ง ์์ต๋๋ค.
๋ค๋ง, ํ์ด์ฌ ๊ฐ์ ์ธ์ด์์๋ ์ฌ๊ทํธ์ถ์ ๋ํ ์ค๋ฒํค๋๋, ๋ฆฌ์คํธ ์ฌ๋ผ์ด์ฑ๊ณผ ๊ฐ์ ์์ ์ผ๋ก ์ธํด ์ค์ ๋ก๋ ์ถ๊ฐ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
def quick_sort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
less = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
greater = [x for x in arr if x > pivot]
return quick_sort(less) + middle + quick_sort(greater)
์๊น ์์์ ํ์ด์ฌ์์ ํต์ ๋ ฌ์ ๊ตฌํํ์๋๋ฐ, ์ ์ฝ๋์์๋
less, middel, greater ๋ผ๋ ํผ๋ฒ์ ๋ฐ๋ผ ๋ถ๋ฅํ ์๋ก์ด ๋ฆฌ์คํธ๋ฅผ ์์ฑํ๋ค.
๋ฐ๋ผ์ ๋ฆฌ์คํธ ์ปดํ๋ฆฌํจ์ ์ ์ฌ์ฉํด ์๋ก์ด ๋ฆฌ์คํธ๋ฅผ ๋ง๋ค๊ธฐ์ ์ถ๊ฐ์ ์ธ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฌ์ฉํ๊ณ ์ ์ฝ๋๋ ํต ์ ๋ ฌ์ ์ ์๋ฆฌ(in-place)ํน์ฑ์ ๋ฒ์ด๋๋ค.
def partition(nums, low, high):
# ํผ๋ฒ์ ์ ํํ๊ณ , ์์ ์์์ ํฐ ์์๋ฅผ ์์ชฝ์ผ๋ก ๋ถํ ํฉ๋๋ค.
pivot = nums[(low + high) // 2]
i = low - 1
j = high + 1
while True:
i += 1
while nums[i] < pivot:
i += 1
j -= 1
while nums[j] > pivot:
j -= 1
if i >= j:
return j
# ํผ๋ฒ์ ๊ธฐ์ค์ผ๋ก ์์ ์์์ ํฐ ์์๋ฅผ ๊ตํํฉ๋๋ค.
nums[i], nums[j] = nums[j], nums[i]
def quick_sort(nums):
# ํต ์ ๋ ฌ์ ๋์ฐ๋ฏธ ํจ์๋ฅผ ์ ์ํฉ๋๋ค.
def _quick_sort(items, low, high):
if low < high:
# ํผ๋ฒ์ ๊ธฐ์ค์ผ๋ก ๋ถํ ๋ ์ง์ ์ ๊ตฌํฉ๋๋ค.
split_index = partition(items, low, high)
# ๋ถํ ๋ ๋ ๋ถ๋ถ์ ์ฌ๊ท์ ์ผ๋ก ์ ๋ ฌํฉ๋๋ค.
_quick_sort(items, low, split_index)
_quick_sort(items, split_index + 1, high)
_quick_sort(nums, 0, len(nums) - 1)
# ํ
์คํธ
nums = [9, 7, 5, 11, 12, 2, 14, 3, 10, 6]
quick_sort(nums)
print(nums) # [2, 3, 5, 6, 7, 9, 10, 11, 12, 14]
์ด ์ฝ๋๋ ํผ๋ฒ์ ์ ํํ๊ณ , ๋ฐฐ์ด ๋ด์์ ์ง์ ์์น๋ฅผ ๋ณ๊ฒฝํ์ฌ ์ ๋ ฌ์ ์ํํ๋ ์ฝ๋์ ๋๋ค.
๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ํ์ธํด๋ณด๋ฉด
120 ๋ฐ์ดํธ๋ฅผ ์๋ณธ๋ฉ๋ชจ๋ฆฌ์ ์ฌ์ฉํ๊ณ ์๋ก์ด ๋ฆฌ์คํธ๋ค์ ํ์ฉํ๊ธฐ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ถ๊ฐ์ ์ผ๋ก ์ฌ์ฉํฉ๋๋ค.
์๋์ ์ฝ๋๋ ๋ฆฌ์คํธ ๋ด๋ถ์์ ์ ๋ ฌ์ ํ๊ธฐ์ (In-place sort) ์ถ๊ฐ์ ์ธ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ์๋ค๊ณ ์๊ฐ๋ฉ๋๋ค.
(์์ง ๋ฉ๋ชจ๋ฆฌ์ ๋ํ ์ดํด๊ฐ ๋ถ์กฑํ์ฌ, ์ฐ์ฐ์ ํ์ํ ๋ฉ๋ชจ๋ฆฌ๋ ์ถ๊ฐ์ ์ธ ๊ณต๋ถํ ์ถ๊ฐ ์์ฑ)
'CS - Roadmap.sh > 3. Common Algorithms' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
3.2. Recursion - 3.2.1 Tail Recursion (0) | 2024.01.21 |
---|---|
3.1. Sorting - 3.1.6 Merge Sort (0) | 2024.01.20 |
3.1 Sorting - 3.1.4 Heap Sort (0) | 2024.01.15 |
3.1. Sorting - 3.1.3 Insertion Sort (0) | 2024.01.15 |
3.1. Sorting - 3.1.2 Selection Sort (1) | 2024.01.14 |