문제: 항목이 비내림차순(오름차순)으로 정렬된 리스트 $S$에 $x$가 항목으로 포함되어 있는가?
입력 파라미터: 리스트 $S$와 값 $x$
리턴값:
# 이분검색 알고리즘
def binsearch(S, x):
low, high = 0, len(S)-1
location = -1
# while 반복문 실행횟수 확인용
loop_count = 0
while low <= high and location == -1:
loop_count += 1
mid = (low + high)//2
if x == S[mid]:
location = mid
elif x < S[mid]:
high = mid - 1
else:
low = mid + 1
return (location, loop_count)
# 이분검색 재귀
def location(S,x, low, high):
if low > high:
return -1
mid = (low + high)//2
if x == S[mid]:
return mid
elif x < S[mid]:
return location(S, x, low, mid-1)
else:
return location(S, x, mid+1, high)
sec = [10, 12, 13, 14, 18, 20, 25, 27, 30, 35, 40, 45, 47]
x = 18
print(location(sec, x, 0, len(sec)-1))
4
location
함수의 인자로 S
와 x
를 추가하였음.location
함수를 임의의 리스트와 임의의 값에 대해 사용하기 위해서.S
와 x
를 인자로 사용하지 않은 이유:location
함수를 재귀로 호출할 때마다 S
와 x
의 값이 매번 새롭게 할당되어 메모리가 많이 사용됨.x
와 S[mid]
비교아래 점화식 성립
\begin{align*} W(n) &= W \Big(\frac n 2 \Big) + 1 \quad \text{if }\, n>1\\ W(1) &= 1 \end{align*}
위 점화식에 대한 해답:
$$W(n) = \lg n + 1$$
점화식 해답 설명
\begin{align*} W(1) &= 1 \\ W(2) &= W(1) + 1 = 2 \\ W(2^2) &= W(2) + 1 = 3 \\ W(2^3) &= W(2^2) + 1 = 4 \\ ... & \\ W(2^k) &= W(2^{k-1}) + 1 = k+1 = \lg (2^k) + 1\\ \end{align*}
아래 최악 시간복잡도 성립
\begin{align*} W(n) &= \lfloor \lg n \rfloor + 1 \in \Theta(\lg n) \end{align*}
증명: 생략
문제: 리스트의 항목을 비내림차순(오름차순)으로 정렬하기
입력 파라미터: 리스트 $S$
리턴값: $S$의 모든 항목을 크기순으로 포함한 리스트
비교횟수 | left | right | 합병결과 |
---|---|---|---|
1 | 10 12 20 27 | 13 15 22 25 | 10 |
2 | 10 12 20 27 | 13 15 22 25 | 10 12 |
3 | 10 12 20 27 | 13 15 22 25 | 10 12 13 |
4 | 10 12 20 27 | 13 15 22 25 | 10 12 13 15 |
5 | 10 12 20 27 | 13 15 22 25 | 10 12 13 15 20 |
6 | 10 12 20 27 | 13 15 22 25 | 10 12 13 15 20 22 |
7 | 10 12 20 27 | 13 15 22 25 | 10 12 13 15 20 22 25 |
10 12 20 27 | 13 15 22 25 | 10 12 13 15 20 22 25 27 |
# 정렬된 두 리스트를 정렬된 리스트로 합병하기
def merge(lList, rList):
mergedList =[]
while len(lList)>0 and len(rList)>0:
if lList[0] < rList[0]:
mergedList.append(lList.pop(0))
else:
mergedList.append(rList.pop(0))
mergedList.extend(lList)
mergedList.extend(rList)
return mergedList
a = [10, 12, 20, 27]
b = [13, 15, 22, 25]
merge(a, b)
[10, 12, 13, 15, 20, 22, 25, 27]
# 합병정렬 재귀
def mergesort(aList):
if len(aList) <= 1:
return aList
mid = len(aList) // 2
lList = mergesort(aList[:mid])
rList = mergesort(aList[mid:])
return merge(lList, rList)
aList = [27, 10, 12, 20, 25, 13, 15, 22]
mergesort(aList)
[10, 12, 13, 15, 20, 22, 25, 27]
merge
) 알고리즘¶def merge_count(lList, rList):
mergedList =[]
count = 0
while len(lList)>0 and len(rList)>0:
count += 1
if lList[0] < rList[0]:
mergedList.append(lList.pop(0))
else:
mergedList.append(rList.pop(0))
mergedList.extend(lList)
mergedList.extend(rList)
print(f"count: {count}")
return mergedList
a1 = [18, 20, 23, 26]
b1 = [13, 15, 17, 27]
merge_count(a1, b1)
count: 7
[13, 15, 17, 18, 20, 23, 26, 27]
a = [10, 12, 16, 18]
b = [19, 20, 22, 27]
merge_count(a, b)
count: 4
[10, 12, 16, 18, 19, 20, 22, 27]
mergesort
) 알고리즘¶merge
함수에서 발생하는 비교연산종료 조건:
$$W(1) = 0$$
위 점화식에 대한 해답:
$$W(n) = n\, \lg n - (n- 1) \in \Theta(n\, \lg n)$$
아래 점화식 성립:
\begin{align*} W(n) &= W \Big(\Big\lfloor \frac n 2 \Big\rfloor\Big) + W \Big(\Big\lceil\frac n 2 \Big\rceil\Big) + (n-1) \end{align*}
따라서 다음 최악 시간복잡도 성립
\begin{align*} W(n) &\in \Theta(n\,\lg n) \end{align*}
mergesort()
함수는 호출될 때마다 매번 aList
인자에 대한 메모리를 새롭게 사용.이유: 파이썬 리스트의 슬라이싱을 사용하기 때문
lList = mergesort(aList[:mid])
rList = mergesort(aList[mid:])
low
와 high
를 추가 인자로 사용하여 주어진 리스트에서 살펴볼 구간을 가리키도록 함.# 제자리 합병정렬 재귀
def mergesort2(aList, low, high):
if (low < high):
mid = (low + high) // 2
lList = mergesort2(aList, low, mid)
rList = mergesort2(aList, mid+1, high)
return merge(lList, rList)
return aList[low:low+1]
aList = [27, 10, 12, 20, 25, 13, 15, 22]
print(mergesort2(aList, 0, 7))
[10, 12, 13, 15, 20, 22, 25, 27]
mergesort
와 mergesort2
공간복잡도¶mergesort
의 추가 메모리 공간복잡도¶merge
를 재귀호출할 때마다 입력 리스트만큼 메모리 추가 사용merge
의 최악 시간복잡도만큼 추가 메모리 사용mergesort
알고리즘의 추가 메모리 일정 공간복잡도는 $\Theta(n \lg n)$mergesort2
의 추가 메모리 공간 복잡도¶mergesort
와 mergesort2
의 실행시간 비교¶merge
함수를 실행할 때 드는 비용이 절대적이기 때문.# 시간 측정을 위한 모듈
import time
bigNum = 1000000
reversedList = list(range(bigNum, 0, -1))
start_time = time.time()
mergesort(reversedList)
end_time = time.time()
duration = end_time - start_time
print(f"걸린시간: {duration:.2f}초")
걸린시간: 95.59초
bigNum = 1000000
reversedList = list(range(bigNum, 0, -1))
start_time = time.time()
mergesort2(reversedList, 0, bigNum)
end_time = time.time()
duration = end_time - start_time
print(f"걸린시간: {duration:.2f}초")
걸린시간: 96.02초