1"""
2์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ (Sorting Algorithms)
3Sorting Algorithms Comparison
4
5๋ค์ํ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ ๊ตฌํ๊ณผ ๋น๊ต์
๋๋ค.
6"""
7
8import random
9import time
10from typing import List
11
12
13# =============================================================================
14# 1. ๋ฒ๋ธ ์ ๋ ฌ (Bubble Sort)
15# =============================================================================
16def bubble_sort(arr: List[int]) -> List[int]:
17 """
18 ๋ฒ๋ธ ์ ๋ ฌ
19 ์๊ฐ: O(nยฒ), ๊ณต๊ฐ: O(1), ์์ ์ ๋ ฌ
20 """
21 arr = arr.copy()
22 n = len(arr)
23
24 for i in range(n):
25 swapped = False
26 for j in range(0, n - i - 1):
27 if arr[j] > arr[j + 1]:
28 arr[j], arr[j + 1] = arr[j + 1], arr[j]
29 swapped = True
30 if not swapped:
31 break
32
33 return arr
34
35
36# =============================================================================
37# 2. ์ ํ ์ ๋ ฌ (Selection Sort)
38# =============================================================================
39def selection_sort(arr: List[int]) -> List[int]:
40 """
41 ์ ํ ์ ๋ ฌ
42 ์๊ฐ: O(nยฒ), ๊ณต๊ฐ: O(1), ๋ถ์์ ์ ๋ ฌ
43 """
44 arr = arr.copy()
45 n = len(arr)
46
47 for i in range(n):
48 min_idx = i
49 for j in range(i + 1, n):
50 if arr[j] < arr[min_idx]:
51 min_idx = j
52 arr[i], arr[min_idx] = arr[min_idx], arr[i]
53
54 return arr
55
56
57# =============================================================================
58# 3. ์ฝ์
์ ๋ ฌ (Insertion Sort)
59# =============================================================================
60def insertion_sort(arr: List[int]) -> List[int]:
61 """
62 ์ฝ์
์ ๋ ฌ
63 ์๊ฐ: O(nยฒ), ์ต์ O(n), ๊ณต๊ฐ: O(1), ์์ ์ ๋ ฌ
64 ๊ฑฐ์ ์ ๋ ฌ๋ ๋ฐ์ดํฐ์ ํจ์จ์
65 """
66 arr = arr.copy()
67 n = len(arr)
68
69 for i in range(1, n):
70 key = arr[i]
71 j = i - 1
72 while j >= 0 and arr[j] > key:
73 arr[j + 1] = arr[j]
74 j -= 1
75 arr[j + 1] = key
76
77 return arr
78
79
80# =============================================================================
81# 4. ๋ณํฉ ์ ๋ ฌ (Merge Sort)
82# =============================================================================
83def merge_sort(arr: List[int]) -> List[int]:
84 """
85 ๋ณํฉ ์ ๋ ฌ
86 ์๊ฐ: O(n log n), ๊ณต๊ฐ: O(n), ์์ ์ ๋ ฌ
87 """
88 if len(arr) <= 1:
89 return arr
90
91 mid = len(arr) // 2
92 left = merge_sort(arr[:mid])
93 right = merge_sort(arr[mid:])
94
95 return merge(left, right)
96
97
98def merge(left: List[int], right: List[int]) -> List[int]:
99 """๋ ์ ๋ ฌ๋ ๋ฐฐ์ด ๋ณํฉ"""
100 result = []
101 i = j = 0
102
103 while i < len(left) and j < len(right):
104 if left[i] <= right[j]:
105 result.append(left[i])
106 i += 1
107 else:
108 result.append(right[j])
109 j += 1
110
111 result.extend(left[i:])
112 result.extend(right[j:])
113 return result
114
115
116# =============================================================================
117# 5. ํต ์ ๋ ฌ (Quick Sort)
118# =============================================================================
119def quick_sort(arr: List[int]) -> List[int]:
120 """
121 ํต ์ ๋ ฌ
122 ์๊ฐ: ํ๊ท O(n log n), ์ต์
O(nยฒ), ๊ณต๊ฐ: O(log n), ๋ถ์์ ์ ๋ ฌ
123 """
124 if len(arr) <= 1:
125 return arr
126
127 pivot = arr[len(arr) // 2]
128 left = [x for x in arr if x < pivot]
129 middle = [x for x in arr if x == pivot]
130 right = [x for x in arr if x > pivot]
131
132 return quick_sort(left) + middle + quick_sort(right)
133
134
135def quick_sort_inplace(arr: List[int], low: int = 0, high: int = None) -> List[int]:
136 """ํต ์ ๋ ฌ (in-place)"""
137 if high is None:
138 arr = arr.copy()
139 high = len(arr) - 1
140
141 if low < high:
142 pivot_idx = partition(arr, low, high)
143 quick_sort_inplace(arr, low, pivot_idx - 1)
144 quick_sort_inplace(arr, pivot_idx + 1, high)
145
146 return arr
147
148
149def partition(arr: List[int], low: int, high: int) -> int:
150 """ํํฐ์
(Lomuto scheme)"""
151 pivot = arr[high]
152 i = low - 1
153
154 for j in range(low, high):
155 if arr[j] <= pivot:
156 i += 1
157 arr[i], arr[j] = arr[j], arr[i]
158
159 arr[i + 1], arr[high] = arr[high], arr[i + 1]
160 return i + 1
161
162
163# =============================================================================
164# 6. ํ ์ ๋ ฌ (Heap Sort)
165# =============================================================================
166def heap_sort(arr: List[int]) -> List[int]:
167 """
168 ํ ์ ๋ ฌ
169 ์๊ฐ: O(n log n), ๊ณต๊ฐ: O(1), ๋ถ์์ ์ ๋ ฌ
170 """
171 arr = arr.copy()
172 n = len(arr)
173
174 # ์ต๋ ํ ๊ตฌ์ฑ
175 for i in range(n // 2 - 1, -1, -1):
176 heapify(arr, n, i)
177
178 # ํ๋์ฉ ์ถ์ถ
179 for i in range(n - 1, 0, -1):
180 arr[0], arr[i] = arr[i], arr[0]
181 heapify(arr, i, 0)
182
183 return arr
184
185
186def heapify(arr: List[int], n: int, i: int):
187 """์ต๋ ํ ์์ฑ ์ ์ง"""
188 largest = i
189 left = 2 * i + 1
190 right = 2 * i + 2
191
192 if left < n and arr[left] > arr[largest]:
193 largest = left
194 if right < n and arr[right] > arr[largest]:
195 largest = right
196
197 if largest != i:
198 arr[i], arr[largest] = arr[largest], arr[i]
199 heapify(arr, n, largest)
200
201
202# =============================================================================
203# 7. ๊ณ์ ์ ๋ ฌ (Counting Sort)
204# =============================================================================
205def counting_sort(arr: List[int]) -> List[int]:
206 """
207 ๊ณ์ ์ ๋ ฌ
208 ์๊ฐ: O(n + k), ๊ณต๊ฐ: O(k), ์์ ์ ๋ ฌ
209 k = ์ต๋๊ฐ - ์ต์๊ฐ + 1
210 ์ ์ ๋ฒ์๊ฐ ์์ ๋ ํจ์จ์
211 """
212 if not arr:
213 return []
214
215 min_val, max_val = min(arr), max(arr)
216 range_val = max_val - min_val + 1
217
218 count = [0] * range_val
219 output = [0] * len(arr)
220
221 # ์นด์ดํธ
222 for num in arr:
223 count[num - min_val] += 1
224
225 # ๋์
226 for i in range(1, range_val):
227 count[i] += count[i - 1]
228
229 # ์ญ์์ผ๋ก ๋ฐฐ์น (์์ ์ฑ ์ ์ง)
230 for i in range(len(arr) - 1, -1, -1):
231 num = arr[i]
232 count[num - min_val] -= 1
233 output[count[num - min_val]] = num
234
235 return output
236
237
238# =============================================================================
239# 8. ๊ธฐ์ ์ ๋ ฌ (Radix Sort)
240# =============================================================================
241def radix_sort(arr: List[int]) -> List[int]:
242 """
243 ๊ธฐ์ ์ ๋ ฌ (LSD)
244 ์๊ฐ: O(d * (n + k)), ๊ณต๊ฐ: O(n + k)
245 d = ์๋ฆฟ์, k = ๊ธฐ์ (๋ณดํต 10)
246 ์์ ๋ฏธ์ง์ ๋ฒ์
247 """
248 if not arr or min(arr) < 0:
249 return sorted(arr) # ์์ ํฌํจ ์ ๊ธฐ๋ณธ ์ ๋ ฌ
250
251 max_val = max(arr)
252
253 exp = 1
254 while max_val // exp > 0:
255 arr = counting_sort_by_digit(arr, exp)
256 exp *= 10
257
258 return arr
259
260
261def counting_sort_by_digit(arr: List[int], exp: int) -> List[int]:
262 """ํน์ ์๋ฆฟ์ ๊ธฐ์ค ๊ณ์ ์ ๋ ฌ"""
263 n = len(arr)
264 output = [0] * n
265 count = [0] * 10
266
267 for num in arr:
268 digit = (num // exp) % 10
269 count[digit] += 1
270
271 for i in range(1, 10):
272 count[i] += count[i - 1]
273
274 for i in range(n - 1, -1, -1):
275 digit = (arr[i] // exp) % 10
276 count[digit] -= 1
277 output[count[digit]] = arr[i]
278
279 return output
280
281
282# =============================================================================
283# ์ฑ๋ฅ ๋น๊ต
284# =============================================================================
285def benchmark_sorts(size: int = 1000):
286 """์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ ์ฑ๋ฅ ๋น๊ต"""
287 arr = [random.randint(0, 10000) for _ in range(size)]
288
289 algorithms = [
290 ("Bubble Sort", bubble_sort, size <= 1000),
291 ("Selection Sort", selection_sort, size <= 1000),
292 ("Insertion Sort", insertion_sort, size <= 1000),
293 ("Merge Sort", merge_sort, True),
294 ("Quick Sort", quick_sort, True),
295 ("Heap Sort", heap_sort, True),
296 ("Counting Sort", counting_sort, True),
297 ("Radix Sort", radix_sort, True),
298 ("Python sorted()", sorted, True),
299 ]
300
301 print(f"\n๋ฐฐ์ด ํฌ๊ธฐ: {size}")
302 print("-" * 50)
303
304 for name, func, should_run in algorithms:
305 if should_run:
306 test_arr = arr.copy()
307 start = time.perf_counter()
308 result = func(test_arr)
309 elapsed = time.perf_counter() - start
310 print(f"{name:20s}: {elapsed * 1000:8.3f} ms")
311 else:
312 print(f"{name:20s}: (ํฌ๊ธฐ ์ด๊ณผ๋ก ์คํต)")
313
314
315# =============================================================================
316# ํ
์คํธ
317# =============================================================================
318def main():
319 print("=" * 60)
320 print("์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ (Sorting Algorithms)")
321 print("=" * 60)
322
323 # ํ
์คํธ ๋ฐฐ์ด
324 arr = [64, 34, 25, 12, 22, 11, 90]
325 print(f"\n์๋ณธ ๋ฐฐ์ด: {arr}")
326 print("-" * 40)
327
328 # ๊ฐ ์๊ณ ๋ฆฌ์ฆ ํ
์คํธ
329 algorithms = [
330 ("๋ฒ๋ธ ์ ๋ ฌ", bubble_sort),
331 ("์ ํ ์ ๋ ฌ", selection_sort),
332 ("์ฝ์
์ ๋ ฌ", insertion_sort),
333 ("๋ณํฉ ์ ๋ ฌ", merge_sort),
334 ("ํต ์ ๋ ฌ", quick_sort),
335 ("ํ ์ ๋ ฌ", heap_sort),
336 ("๊ณ์ ์ ๋ ฌ", counting_sort),
337 ("๊ธฐ์ ์ ๋ ฌ", radix_sort),
338 ]
339
340 for name, func in algorithms:
341 result = func(arr.copy())
342 print(f"{name}: {result}")
343
344 # ์ฑ๋ฅ ๋น๊ต
345 print("\n" + "=" * 60)
346 print("์ฑ๋ฅ ๋น๊ต (Performance Benchmark)")
347 print("=" * 60)
348
349 for size in [100, 1000, 5000]:
350 benchmark_sorts(size)
351
352 # ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ ๋น๊ตํ
353 print("\n" + "=" * 60)
354 print("์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ ๋น๊ต")
355 print("=" * 60)
356 print("""
357 | ์๊ณ ๋ฆฌ์ฆ | ํ๊ท | ์ต์
| ๊ณต๊ฐ | ์์ ์ฑ | ํน์ง |
358 |-------------|----------|----------|--------|-------|---------------------|
359 | ๋ฒ๋ธ ์ ๋ ฌ | O(nยฒ) | O(nยฒ) | O(1) | ์์ | ๋จ์, ๊ต์ก์ฉ |
360 | ์ ํ ์ ๋ ฌ | O(nยฒ) | O(nยฒ) | O(1) | ๋ถ์์ | ๋จ์, ๊ตํ ํ์ ์ ์ |
361 | ์ฝ์
์ ๋ ฌ | O(nยฒ) | O(nยฒ) | O(1) | ์์ | ๊ฑฐ์ ์ ๋ ฌ๋ ๋ฐ์ดํฐ์ ์ข์|
362 | ๋ณํฉ ์ ๋ ฌ | O(nlogn) | O(nlogn) | O(n) | ์์ | ์ผ์ ํ ์ฑ๋ฅ |
363 | ํต ์ ๋ ฌ | O(nlogn) | O(nยฒ) | O(logn)| ๋ถ์์ | ํ๊ท ์ ์ผ๋ก ๊ฐ์ฅ ๋น ๋ฆ |
364 | ํ ์ ๋ ฌ | O(nlogn) | O(nlogn) | O(1) | ๋ถ์์ | in-place, ์ผ์ ํ ์ฑ๋ฅ|
365 | ๊ณ์ ์ ๋ ฌ | O(n+k) | O(n+k) | O(k) | ์์ | ์ ์, ๋ฒ์ ์์ ๋ |
366 | ๊ธฐ์ ์ ๋ ฌ | O(d(n+k))| O(d(n+k))| O(n+k) | ์์ | ์๋ฆฟ์ ๊ธฐ๋ฐ |
367
368 ์ค๋ฌด ์ ํ ๊ฐ์ด๋:
369 - ์ผ๋ฐ์ ์ธ ๊ฒฝ์ฐ: ํต ์ ๋ ฌ ๋๋ ์ธ์ด ๋ด์ฅ ์ ๋ ฌ
370 - ์์ ์ฑ ํ์: ๋ณํฉ ์ ๋ ฌ
371 - ๋ฉ๋ชจ๋ฆฌ ์ ํ: ํ ์ ๋ ฌ
372 - ๊ฑฐ์ ์ ๋ ฌ๋จ: ์ฝ์
์ ๋ ฌ
373 - ์ ์ + ๋ฒ์ ์์: ๊ณ์/๊ธฐ์ ์ ๋ ฌ
374 """)
375
376
377if __name__ == "__main__":
378 main()