1.
알고리즘의 정의
•
어떤 문제를 컴퓨터로 풀기 위한 효율적인 절차
•
문제를 푸는 단계별 절차를 명확하게 기술
2.
알고리즘을 공부하는 목적
•
다양한 문제 해결 방법(=알고리즘 설계 기법)을 공부함.
알고리즘
→ 어떤 문제의 모든 입력 사례에 대해서 해답을 찾아주는 단계별 절차
1.1 sequential search 순차 검색
def seqsearch (n, S, x):
location = 1
while (location <= n and S[location] != x):
location += 1
if (location > n):
location = 0
return location
Python
복사
1.2 Add Array Elements 리스트 합 구하기
def sum (n, S):
result = 0
for i in range(1, n + 1):
result = result + S[i]
return result
Python
복사
1.3 오름차순 정렬 Exchange Sort(교환 정렬)
def exchange (S):
n = len(S)
for i in range(n - 1):
for j in range(i + 1, n):
if (S[i] > S[j]):
S[i], S[j] = S[j], S[i] #swap
Python
복사
1.4 행렬 곱셈 Matrix Multiplication
def matrixmult (A, B):
n = len(A)
C = [[0] * n for _ in range(n)]
for i in range(n):
for j in range(n):
for k in range(n):
C[i][j] += A[i][k] * B[k][j]
return C
Python
복사
알고리즘의 효율성
알고리즘의 성능: 시간과 공간 사용량의 효율성
순차 탐색 vs 이분 검색(binary search)
•
입력 리스트의 조건에 따른 탐색 알고리즘의 선택
- 정렬되지 않은 리스트에서 키 찾기: 순차 탐색
- 정렬된 리스트에서 키 찾기 : 이분 검색
이분 검색
주어진 리스트 S와 키 x에 대해서,
먼저 x를 리스트의 중앙에 위치한 원소와 비교
만약 같으면, 찾았으므로 알고리즘을 종료
만약 x가 그 원소보다 작으면 x는 왼쪽에 있을 것이므로 왼쪽 리스트에 대해서 이진탐색 실행(재귀 호출)
만약 x가 그 원소보다 크면 x는 오른쪽에 있을 것이므로 오른쪽 리스트에 대해 이진 탐색 실행(재귀 호출)
더 이상 찾을 리스트가 없으면 알고리즘을 종료
1.5 Binary Search( Iterative) 이진 탐색 이분 검색
def binsearch(n, S, x):
low = 1
high = n
location = 0
while(low <= high and location == 0):
mid = (low + high) //2
if (x == S[mid]):
location = mid
elif (x < S[mid]):
high = mid -1
else:
low = mid + 1
return location
Python
복사
1.6 n-th Fibonacci Term (Recursive) n번째 피보나치수 찾기(재귀)
def fib(n):
if n <= 1:
return n
else:
return fib(n-1) + fib(n-2)
Python
복사
→ 비효율적임. 예를 들어 fib(5)실행하면 fib(1)은 4번이나 호출됨
1.7 n-th Fibonacci Term (Iterative) n번째 피보나치수 찾기(반복)
def fib2 (n):
f = [0] * (n+1)
if n> 0:
f[1] = 1
for i in range(2, n+1):
f[i] = f[i-1] + f[i-2]
return f[n]
Python
복사
분할정복법(Divide-and-Conquer)
2.1 Binary Search (Recursive) 이분검색 (재귀)
def location(S, low, high):
if low > high:
return 0
else:
mid = (low + high)//2
if x == S[mid]:
return mid
elif x < S[mid]:
return location(S, low, mid -1)
else:
return location(S, mid+1, high)
Python
복사
2.2 Merge Sort 합병정렬 - 사실상 가르고 붙이기
def mergesort(S):
n = len(S)
if n <= 1:
return S
else:
mid = n // 2
U = mergesort(S[0:mid])
V = mergesort(S[mid:n])
return merge(U, V)
Python
복사
2.3 Merge 합병 - 여기서 사실상 정렬
def merge(U, V):
S = []
i = j = 0
while (i < len(U) and j < len(V)):
if (U[i] < V[j]):
S.append(U[i])
i += 1
else:
S.append(V[j])
j += 1
if i < len(U):
S += U[i : len(U)]
else:
S += V[j : len(V)]
return S
Python
복사
2.4 MergeSort2 (Enhanced Merge Sort)
def mergesort2 (S, low, high):
if low < high :
mid = (low + high) // 2
mergesort2(S, low, mid)
mergesort2(S, mid + 1, high)
merge2(S, low, mid, high)
Python
복사
2.5 Merge 2(Enhanced Merge)
def merge2(S, low, mid, high):
U = []
i = low
j = mid + 1
while( i <= mid and j <= high):
if(S[i] < S[j]):
U.append(S[i])
i += 1
else:
U.append(S[j])
j += 1
if i <= mid:
U += S[i : mid + 1]
else:
U += S[j : high + 1]
for k in range(low, high + 1):
S[k] = U[k-low]
Python
복사
2.6 Quick-Sort (퀵솔트)
def quicksort (S, low, high):
if (high > low):
pivotpoint = partition(S, low, high)
quicksort(S, low, pivotpoint - 1)
quicksort(S, pivotpoint + 1, high)
Python
복사
기준 원소(pivot)는 어떻게 정할까?
편의상, 일단 리스트의 첫 원소를 기준 원소로 정하도록 하자
2.7 Partition(for QuickSort)
def partition (S, low, high):
pivotitem = S[low]
j = low
for i in range(low + 1, high + 1):
if (S[i] < pivotitem):
j += 1;
S[i], S[j] = S[j], S[i] # swap
pivotpoint = j
S[low], S[pivotpoint] = S[pivotpoint], S[low] # swap
return pivotpoint
Python
복사
동적계획법(Dynamic Programming)
-문제를 더 작은 문제로 분할하되, 상향식으로 문제를 해결한다.
1.
문제를 해결할 수 있는 재귀 관계식을 구한다.(점화식)
2.
가장 작은 입력 사례로부터 상향식 방법으로 문제를 해결한다.
분할정복법 vs 동적계획법
-문제를 작은 사례로 분할하여 해결한다는 점에서 동일
분할정복: 재귀 호출을 통해 분할하여 정복 (Top - Down)
동적 계획: 메모이제이션을 통해 상향식으로 정복 (Bottom- up)
ex) 피보나치 수열
이항계수는 뛰어넘고.
최단경로(플로이드 알고리즘)
-주어진 그래프에서 모든 정점의 쌍에 대한 최단 경로를 구하시오.
*단순무식한 방법
-각 정점에서 다른 정점으로 가는 모든 경로를 구한 뒤 그 경로들 중에서 가장 짧은 경로 찾기
효율성 (n-2)!
그래프의 표현 : 인접 행렬(adjacency matrix)
1단계 : 재귀관계식을 찾는다.
-D : 각 정점의 쌍이 가지는 최단 경로의 길이를 나타내는 행렬
-D[i][j] : Vi 에서 Vj로 가는 최단 경로의 길이
2단계: 상향식 방법으로 해답을 구한다
3.1 Floyd’s Algorithm for Shortest Path
def floyd(W):
D = W
n = len(W)
for k in range(n):
for i in range(n):
for j in range(n):
D[i][j] = min(D[i][j], D[i][k] + D[k][j])
return D
Python
복사
최단 경로는요?
P[i][j] : Vi에서 Vj로 가는 최단 경로가 거쳐야하는 새로운 정점
최단 경로의 중간에 놓여있는 정점이 없는 경우에는 -1
3.2 Floyd’s Algorithm for Shortest Path 2
def floyd2(W):
n = len(W)
D = W
P = [[-1] * n for _ in range(n)]
for k in range(n):
for i in range(n):
for j in range(n):
if (D[i][j] > D[i][k] + D[k][j]):
D[i][j] = D[i][k] + D[k][j]
P[i][j] = k
return D, P
Python
복사
P[i][j] = -1 이면, 간선 (Vi, Vj)가 최단 경로임.
P[i][j] = k인 경우 inorder 탐색 (Vi, Vk)의 최단경로 출력 후 Vk를 출력하고 (Vk, Vj)의 최단경로 출력
3.3 Print Shortet Path
def path(P, u, v):
if(P[u][v] != -1):
path(P, u, P[u][v])
print('v%d' %(P[u][v]), end = '-> ')
path(P, P[u][v], v)
Python
복사