7. ์๊ณ ๋ฆฌ์ฆ
์๊ฐ, ๊ณต๊ฐ ๋ณต์ก๋
-
๋ณต์ก๋: ์๊ณ ๋ฆฌ์ฆ์ ์ฑ๋ฅ์ ํ๊ฐํ๋ ์ฒ๋๋กย **์๊ฐ ๋ณต์ก๋(Time Complexity)**์ย **๊ณต๊ฐ ๋ณต์ก๋(Space Complexity)**๋ก ๋๋๋ค.
- ์๊ฐ ๋ณต์ก๋(Time Complexity): ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉ๋๋ ์ฐ์ฐ ํ์์ ์ด๋
- ๊ณต๊ฐ ๋ณต์ก๋(Space Complexity): ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉ๋๋ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ์ด๋
์ฆ, ์๊ฐ ๋ณต์ก๋๋ ์๋์ ๋ํ ๋ถ์ ๊ฒฐ๊ณผ์ด๊ณ , ๊ณต๊ฐ ๋ณต์ก๋๋ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ๋ํ ๋ถ์ ๊ฒฐ๊ณผ์ด๋ค.
-
๋ณต์ก๋ ํ๊ธฐ๋ฒ
- O Notation (๋น ์ค ํ๊ธฐ๋ฒ): ์ ๊ทผ์ ์ํ์ / ์ต์ ์ ๊ฒฝ์ฐ
- ฮฉ Notation (์ค๋ฉ๊ฐ ํ๊ธฐ๋ฒ): ์ ๊ทผ์ ํํ์ / ์ต์์ ๊ฒฝ์ฐ
- ฮธ Notation (์ธํ ํ๊ธฐ๋ฒ): ์ ๊ทผ์ ์ํ์ ๊ณผ ์ ๊ทผ์ ํํ์ ์ ๊ต์งํฉ / ํ๊ท ์ ๊ฒฝ์ฐ
Sort Algorithm
Bubble Sort
-
๋ฐฐ์ด์ 0๋ฒ๋ถํฐ N-1๋ฒ๊น์ง ํ์์ ํ๋ฉด์ ์ธ์ ํ ์นธ๊ณผ ๋น๊ตํ์ฌ swap์ ํ๋ ๋ฐฉ์์ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ด๋ค.
-
์๊ฐ๋ณต์ก๋
์ด๋ค. -
ํ์ด์ฌ ๊ตฌํ
def bubbleSort(alist): for passnum in range(len(alist)-1, 0, -1): for i in range(passnum): if alist[i] > alist[i+1]: temp = alist[i] alist[i] = alist[i+1] alist[i+1] = temp
Selection Sort
- ์ ๋ ฌ๋์ง ์์ ๋ถ๋ถ์์ ์ต๋๊ฐ(๋๋ ์ต์๊ฐ)์ ์ฐพ์ ํ์ฌ ์์น์ ์์์ ๊ตํํ๋ ๋ฐฉ์.
- ํน์ง: ๋น๊ต ํ์๋ ๋ง์ง๋ง swap ํ์๋ ์ต์ํ๋จ.
- ์๊ฐ ๋ณต์ก๋:
- ํ์ด์ฌ ๊ตฌํ
def selectionSort(alist):
for fillslot in range(len(alist)-1, 0, -1):
positionOfMax = 0
for location in range(1, fillslot+1):
if alist[location] > alist[positionOfMax]:
positionOfMax = location
alist[fillslot], alist[positionOfMax] = alist[positionOfMax], alist[fillslot]
Insertion Sort
- ํ์ฌ๊น์ง ์ ๋ ฌ๋ ๋ถ๋ถ์ ์๋ก์ด ์์๋ฅผ ์ ์ ํ ์์น์ "์ฝ์ "ํ๋ ๋ฐฉ์.
- ์๊ฐ ๋ณต์ก๋:
- ์ต์
/ํ๊ท :
- ์ต์ (๊ฑฐ์ ์ ๋ ฌ๋ ๊ฒฝ์ฐ):
- ์ต์
/ํ๊ท :
- ํ์ด์ฌ ๊ตฌํ
def insertion_sort(collection):
for index in range(1, len(collection)):
while index > 0 and collection[index] < collection[index - 1]:
collection[index], collection[index - 1] = collection[index - 1], collection[index]
index -= 1
return collection
Merge Sort
- Divide & Conquer ๋ฐฉ์์ผ๋ก ๋ฐฐ์ด์ ๋ฐ์ผ๋ก ๋ถํ ํ ํ ์ฌ๊ท์ ์ผ๋ก ์ ๋ ฌ, ๋ ๋ฐฐ์ด์ ๋ณํฉํ๋ ๋ฐฉ์.
- ํน์ง: ์์ ์ ๋ ฌ, ์ถ๊ฐ ๋ฉ๋ชจ๋ฆฌ ํ์.
- ์๊ฐ ๋ณต์ก๋:
- ํ์ด์ฌ ๊ตฌํ
def merge_sort(lst):
if len(lst) <= 1:
return lst
mid = len(lst) // 2
left = merge_sort(lst[:mid])
right = merge_sort(lst[mid:])
return merge(left, right)
Heap Sort
- ์ฃผ์ด์ง ๋ฐฐ์ด์ ์ต๋ ํ(๋๋ ์ต์ ํ)์ผ๋ก ๊ตฌ์ฑํ ํ, ๋ฃจํธ์ ๋ง์ง๋ง ์์๋ฅผ ๊ตํํ๋ฉฐ ์ ๋ ฌ.
- ํน์ง: in-place ์ ๋ ฌ, ๋น๊ต ๊ธฐ๋ฐ ์ ๋ ฌ.
- ์๊ฐ ๋ณต์ก๋:
- ํ์ด์ฌ ๊ตฌํ
def heapify(arr, index, heap_size):
largest = index
left = 2 * index + 1
right = 2 * index + 2
if left < heap_size and arr[left] > arr[largest]:
largest = left
if right < heap_size and arr[right] > arr[largest]:
largest = right
if largest != index:
arr[index], arr[largest] = arr[largest], arr[index]
heapify(arr, largest, heap_size)
def heap_sort(arr):
n = len(arr)
for i in range(n//2 - 1, -1, -1):
heapify(arr, i, n)
for i in range(n-1, 0, -1):
arr[0], arr[i] = arr[i], arr[0]
heapify(arr, 0, i)
return arr
Quick Sort
- ๊ธฐ์ค(pivot)์ ์ ํด pivot๋ณด๋ค ์์ ์์์ ํฐ ์์๋ก ๋ถํ ํ๊ณ , ๋ถํ ๋ ๋ฐฐ์ด์ ๋ํด ์ฌ๊ท์ ์ผ๋ก ์ ๋ ฌ.
- ํน์ง: ํ๊ท ์ ์ผ๋ก ๋งค์ฐ ๋น ๋ฅด์ง๋ง, pivot ์ ํ์ ๋ฐ๋ผ ์ต์ ์ ๊ฒฝ์ฐ O(Nยฒ) ๋ฐ์ ๊ฐ๋ฅ.
- ์๊ฐ ๋ณต์ก๋:
- ์ต์
:
- ํ๊ท /์ต์ :
- ์ต์
:
- ํ์ด์ฌ ๊ตฌํ
def quickSort(alist):
quickSortHelper(alist, 0, len(alist)-1)
def quickSortHelper(alist, first, last):
if first < last:
splitpoint = partition(alist, first, last)
quickSortHelper(alist, first, splitpoint-1)
quickSortHelper(alist, splitpoint+1, last)
def partition(alist, first, last):
pivotvalue = alist[first]
leftmark = first + 1
rightmark = last
done = False
while not done:
while leftmark <= rightmark and alist[leftmark] <= pivotvalue:
leftmark += 1
while rightmark >= leftmark and alist[rightmark] >= pivotvalue:
rightmark -= 1
if rightmark < leftmark:
done = True
else:
alist[leftmark], alist[rightmark] = alist[rightmark], alist[leftmark]
alist[first], alist[rightmark] = alist[rightmark], alist[first]
return rightmark
Divide and Conquer
- ๊ฐ๋ : ํฐ ๋ฌธ์ ๋ฅผ ์ฌ๋ฌ ๊ฐ์ ํ์ ๋ฌธ์ ๋ก ๋ถํ ํ ํ, ๊ฐ ํ์ ๋ฌธ์ ๋ฅผ ๋ ๋ฆฝ์ ์ผ๋ก ํด๊ฒฐํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ๊ฒฐํฉํ๋ ๋ฐฉ์.
- ์์: ์ฌ๊ท์ ํผ๋ณด๋์น ๊ณ์ฐ
def fibb(n):
if n <= 1:
return 1
return fibb(n-1) + fibb(n-2)
- ํน์ง: ์ฌ๊ท ํธ์ถ์ ํตํ ๋ฌธ์ ๋ถํ , ๋ณํฉ ๋จ๊ณ๊ฐ ์ค์ํ ์ญํ .
Dynamic Programming
-
๊ฐ๋ : ์ค๋ณต๋๋ ํ์ ๋ฌธ์ ์ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅ(๋ฉ๋ชจ์ด์ ์ด์ ๋๋ ํ๋ทธ๋ ์ด์ )ํ์ฌ ํจ์จ์ ์ผ๋ก ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ.
-
ํํฅ์์ ๊ทผ๋ฒ (Top-Down, ๋ฉ๋ชจ์ด์ ์ด์ ): ์ฌ๊ท ํธ์ถ ์ค ์ด๋ฏธ ๊ณ์ฐ๋ ๊ฒฐ๊ณผ๋ ์ ์ฅํ์ฌ ์ฌํ์ฉ.
table = [None] * (n+1)
def fibb(n):
if n <= 1:
return 1
if table[n] is not None:
return table[n]
table[n] = fibb(n-1) + fibb(n-2)
return table[n]
- ์ํฅ์ (Bottom-Up, ํ๋ทธ๋ ์ด์ ): ์์ ๋ฌธ์ ๋ถํฐ ์ฐจ๋ก๋๋ก ๊ณ์ฐํ์ฌ ํ ์ด๋ธ์ ์ ์ฅ.
def fibb(n):
table = [1] * (n+1)
for i in range(2, n+1):
table[i] = table[i-1] + table[i-2]
return table[n]
Greedy Algorithm
- ๊ฐ๋ : ๊ฐ ๋จ๊ณ์์ ์ง์ญ์ ์ผ๋ก ์ต์ ์ ์ ํ์ ํ์ฌ ์ ์ฒด ๋ฌธ์ ์ ์ต์ ํด๋ฅผ ๊ตฌํ๋ ๋ฐฉ์.
- ์์: ๋์ ๊ฑฐ์ค๋ฆ๋ ๋ฌธ์ โ ๋์ ์ ๋จ์๊ฐ 1, 5, 10์์ผ ๊ฒฝ์ฐ ๊ทธ๋ฆฌ๋ ์ ํ์ด ๊ฐ๋ฅํ์ง๋ง, 1, 7, 10์์ธ ๊ฒฝ์ฐ์๋ ์ต์ ํด๋ฅผ ๋ณด์ฅํ์ง ์์.
- ์ฃผ์์ : ๊ทธ๋ฆฌ๋ ์ ํ์ด ์ ์ฒด ์ต์ ํด๋ฅผ ๋ณด์ฅํ๋์ง ๊ฒ์ฆ์ด ํ์
Graph
- ๊ฐ๋ : ์ ์ (๋ ธ๋)๊ณผ ๊ฐ์ (์ฃ์ง)์ผ๋ก ๊ตฌ์ฑ๋ ์๋ฃ๊ตฌ์กฐ.
- ํ์ฉ: ๊ฒฝ๋ก ํ์, ์ต๋จ ๊ฒฝ๋ก, ๋คํธ์ํฌ ์ฐ๊ฒฐ ๋ฑ ๋ค์ํ ๋ฌธ์ ํด๊ฒฐ์ ์ฌ์ฉ๋จ.
Graph Traversal: BFS, DFS
- BFS (๋๋น ์ฐ์ ํ์)
- ๋ฐฉ์: ์์ ๋ ธ๋์์ ์ธ์ ํ ๋ ธ๋๋ฅผ ๋จผ์ ๋ฐฉ๋ฌธํ๋ฉฐ, Queue๋ฅผ ์ฌ์ฉ.
- ์ฅ์ : ์ต๋จ ๊ฒฝ๋ก ๋ณด์ฅ, ๋ ธ๋ ์๊ฐ ์ ๊ณ ๊น์ด๊ฐ ์์ ๊ฒฝ์ฐ ๋น ๋ฆ.
- ๋จ์ : ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ๋ง์์ง ์ ์์.
- DFS (๊น์ด ์ฐ์ ํ์)
- ๋ฐฉ์: ํ ๋ฐฉํฅ์ผ๋ก ๊น๊ฒ ํ์ ํ, ๋ ์ด์ ์งํํ ์ ์์ผ๋ฉด ์ด์ ๋จ๊ณ๋ก ๋์๊ฐ. ์ฃผ๋ก Stack์ด๋ ์ฌ๊ท ์ฌ์ฉ.
- ์ฅ์ : ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ๋น๊ต์ ์ ์, ๊ตฌํ์ด ๊ฐ๋จํจ.
- ๋จ์ : ์ต๋จ ๊ฒฝ๋ก ๋ณด์ฅ์ด ์ด๋ ค์.
Shortest Path
- ๊ฐ๋ : ๊ทธ๋ํ ๋ด์์ ํ ๋ ธ๋์์ ๋ค๋ฅธ ๋ ธ๋๋ก ๊ฐ๋ ์ต๋จ ๊ฒฝ๋ก(์ต์ ๋น์ฉ ๊ฒฝ๋ก)๋ฅผ ์ฐพ๋ ๋ฌธ์ .
- ์๊ณ ๋ฆฌ์ฆ: Dijkstra, Floyd-Warshall, Bellman-Ford ๋ฑ์ด ์์.
Dijkstra
- ํน์ง: ์์ ๋ ธ๋์์ ๋ค๋ฅธ ๋ชจ๋ ๋ ธ๋๊น์ง์ ์ต๋จ ๊ฑฐ๋ฆฌ๋ฅผ ๊ตฌํ๋ฉฐ, ์์ ๊ฐ์ค์น๋ ํ์ฉํ์ง ์์.
- ๋์ ๋ฐฉ์:
- ์์ ๋ ธ๋๋ฅผ 0, ๋๋จธ์ง๋ INF๋ก ์ด๊ธฐํ.
- ๊ฐ์ฅ ์งง์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ฐ์ง ๋ ธ๋๋ฅผ ์ ํ ํ ์ธ์ ๋ ธ๋์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ฐฑ์ .
- ์ฐ์ ์์ ํ๋ฅผ ์ฌ์ฉํ๋ฉด ์๊ฐ ๋ณต์ก๋ O(E log V) ๋ฌ์ฑ ๊ฐ๋ฅ.
- ํ์ด์ฌ ๊ตฌํ (ํต์ฌ ๋ถ๋ถ)
import heapq
INF = int(1e9)
def dijkstra(start, graph, distance):
q = []
heapq.heappush(q, (0, start))
distance[start] = 0
while q:
dist, now = heapq.heappop(q)
if distance[now] < dist:
continue
for next_node, cost in graph[now]:
new_cost = dist + cost
if distance[next_node] > new_cost:
distance[next_node] = new_cost
heapq.heappush(q, (new_cost, next_node))
Floyd-Warshall
- ํน์ง: ๋ชจ๋ ์ ์ ์์ ๋ํด ์ต๋จ ๊ฒฝ๋ก๋ฅผ ๊ตฌํ๋ ์๊ณ ๋ฆฌ์ฆ.
- ๋์ ๋ฐฉ์:
- ์ ํ์: D[a][b] = min(D[a][b], D[a][k] + D[k][b])
- ์ผ์ค ๋ฐ๋ณต๋ฌธ์ ์ฌ์ฉํ์ฌ ๋ชจ๋ ์ค๊ฐ ์ ์ ์ ๊ณ ๋ ค.
- ์๊ฐ ๋ณต์ก๋: O(Vยณ)
- ํ์ด์ฌ ๊ตฌํ (ํต์ฌ ๋ถ๋ถ)
for k in range(1, n+1):
for i in range(1, n+1):
for j in range(1, n+1):
graph[i][j] = min(graph[i][j], graph[i][k] + graph[k][j])
Bellman-Ford
- ํน์ง: ์์ ๊ฐ์ค์ง ๊ฐ์ ์ด ์๋ ๊ฒฝ์ฐ์๋ ์ต๋จ ๊ฒฝ๋ก๋ฅผ ๊ตฌํ๋ฉฐ, ์์ ์ฌ์ดํด ํ์ง๊ฐ ๊ฐ๋ฅํจ.
- ๋์ ๋ฐฉ์:
- ๋ชจ๋ ๊ฐ์ ์ V-1๋ฒ ๋ฐ๋ณตํ๋ฉฐ ์ต๋จ ๊ฑฐ๋ฆฌ๋ฅผ ๊ฐฑ์ .
- ํ ๋ฒ ๋ ๋ฐ๋ณตํ์ฌ ๊ฐฑ์ ์ด ์ผ์ด๋๋ฉด ์์ ์ฌ์ดํด ์กด์ฌ.
- ์๊ฐ ๋ณต์ก๋: O(V ร E)
- ํ์ด์ฌ ๊ตฌํ (ํต์ฌ ๋ถ๋ถ)
def bellman_ford(start, edges, dist, n):
dist[start] = 0
for i in range(n):
for u, v, cost in edges:
if dist[u] != INF and dist[v] > dist[u] + cost:
dist[v] = dist[u] + cost
if i == n - 1:
return True # ์์ ์ฌ์ดํด ์กด์ฌ
return False
Minimum Spanning Tree
- ๊ฐ๋ : ๋ชจ๋ ์ ์ ์ ์ฐ๊ฒฐํ๋ฉด์ ๊ฐ์ ์ ๊ฐ์ค์น ํฉ์ด ์ต์์ธ ํธ๋ฆฌ.
- ์๊ณ ๋ฆฌ์ฆ: Prim, Kruskal ๋ฑ์ด ์์.
Prim
- ํน์ง: ์์ ์ ์ ์์๋ถํฐ ์ธ์ ํ ์ ์ ์ค ์ต์ ๊ฐ์ค์น ๊ฐ์ ์ ์ ํํ๋ฉฐ MST๋ฅผ ํ์ฅ.
- ์๊ฐ ๋ณต์ก๋: ๊ธฐ๋ณธ์ ์ผ๋ก O(nยฒ) (์ฐ์ ์์ ํ ์ฌ์ฉ ์ ๊ฐ์ ๊ฐ๋ฅ)
- ๋์ ๋ฐฉ์:
- ์์ ์ ์ ์ MST์ ํฌํจ.
- ์ธ์ ๋
ธ๋ ์ค ์ต์ ๋น์ฉ์ ๋
ธ๋๋ฅผ ์ ํ ํ MST ํ์ฅ.
Kruskal
- ํน์ง: ๊ฐ์ ์ ๊ฐ์ค์น ์ค๋ฆ์ฐจ์์ผ๋ก ์ ๋ ฌํ ํ, ์ฌ์ดํด์ ํ์ฑํ์ง ์๋ ๊ฐ์ ์ ์ ํํด MST ๊ตฌ์ฑ.
- ์๊ฐ ๋ณต์ก๋: O(e log e)
- ๋์ ๋ฐฉ์:
- ๋ชจ๋ ๊ฐ์ ์ ์ ๋ ฌ.
- Union-Find ์๋ฃ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํด ์ฌ์ดํด ์ฌ๋ถ๋ฅผ ํ๋ณํ๋ฉฐ ๊ฐ์ ์ ํ.