Divide and Conquer (Merge sort, min max 찾기)

Divide and Conquer (분할정복법)은 주어진 문제를 작은 Problem으로 나누고 작은 Problem들을 해결하여 정복하는 방법입니다.

나눈 작은 Problem의 해답을 얻을 수 있으면 답을 구하고 그렇지 않으면 더 작은 Problem으로 다시 나눠줍니다.

즉 답을 구할 수 있는 만큼 충분히 Problem을 나눠주고 답을 구하는 방법입니다.


Divide and Conquer Algorithm 전략

  • 전체 Problem을 여러 작은 Problem들로 분할해줍니다.
  • 분할(Divide)된 Problem들을 각각 정복(Conquer)해줍니다.
  • 작은 Problem을 통해 얻은 해답을 통합하여 원래의 Problem을 해결합니다.


Divide and Conquer를 통한 최대값, 최솟값 찾기

 def divide_conquer(n):
     if len(n) <= 1:                     # list n의 크기가 1이면 return해줍니다.
         return n
     mid = len(n) // 2                   #len(n)/2 를 해주어 mid 변수에 저장해줍니다.
     left = n[:mid]                      #list n에서 첫번째부터 mid 전 까지 left로 저장해줍니다. 
     right = n[mid:]                     #list n에서 mid부터 마지막까지 right로 저장해줍니다.
     left = divide_conquer(left)         #recursion을 이용하여 왼쪽list를 다시 반으로 나눕니다.
     right = divide_conquer(right)       #recursion을 이용하여 오른쪽list를 다시 반으로 나눕니다.
     return conquer(left, right)         # 함수 conquer로 이동하여줍니다.

 def conquer(L, R):
     result = []                         #정렬된 값을 저장할 list를 만들어줍니다.
     while len(L) > 0 or len(R) > 0:     #L과R의 list가 모두 사용될 때 까지 반복해줍니다.
         if len(L) > 0 and len(R) > 0:   #L과R list에 값이 모두 남아있다면
             if L[0] <= R[0]:            #만약 L[0]값이 R[0]보다 작다면 
                 result.append(L[0])     #결과값에 L[0]을 추가해줍니다.
                 L = L[1:]               #그리고 L[0]는 제거해주고 앞으로 한칸씩 당겨줍니다.
             else:                       #반대 라면
                 result.append(R[0])     #결과값에 R[0]을 추가해줍니다.
                 R = R[1:]               #그리고 R[0]는 제거해주고 앞으로 한칸씩 당겨줍니다.
         elif len(L) > 0:                #만약 L list에 값만 남았다면
             result.append(L[0])         #L list 자체는 sort가 되있으므로 
             L = L[1:]                   #결과값에 순서대로 넣어줍니다.   
         elif len(R) > 0:                #만약 R list에 값만 남았다면
             result.append(R[0])         #R list 자체는 sort가 되있으므로
             R = R[1:]                   #결과값에 순서대로 넣어줍니다.
     return minmax(result)               #최종 결과값을 minmax 함수로 이동시켜줍니다.

 def minmax(n):                          #최종 결과값은 오름차순으로 정렬되어있기 때문에
     my_min = n[0]                       #최솟값은 0번째에 위치하고
     my_max = n[-1]                      #최대값은 -1번째에 위치할것 입니다.
     return my_min, my_max               #이들을 뽑아준 뒤 return하여 줍니다.

 l = [3,8,5,7,6,1,2,9,11]
 print("(Min,Max)=",divide_conquer(l))
 


Divide and Conquer를 통한 Merge Sort 알고리즘

def mergesort(n):
    if len(n) <= 1:                     # list n의 크기가 1이면 return해줍니다.
        return n
    mid = len(n) // 2                   #len(n)/2 를 해주어 mid 변수에 저장해줍니다.
    left = n[:mid]                      #list n에서 첫번째부터 mid 전 까지 left로 저장해줍니다. 
    right = n[mid:]                     #list n에서 mid부터 마지막까지 right로 저장해줍니다.
    left = mergesort(left)              #recursion을 이용하여 왼쪽list를 다시 반으로 나눕니다.
    right = mergesort(right)            #recursion을 이용하여 오른쪽list를 다시 반으로 나눕니다.
    return conquer(left, right)         # 함수 conquer로 이동하여줍니다.

def conquer(L, R):
    result = []                         #정렬된 값을 저장할 list를 만들어줍니다.
    while len(L) > 0 or len(R) > 0:     #L과R의 list가 모두 사용될 때 까지 반복해줍니다.
        if len(L) > 0 and len(R) > 0:   #L과R list에 값이 모두 남아있다면
            if L[0] <= R[0]:            #만약 L[0]값이 R[0]보다 작다면 
                result.append(L[0])     #결과값에 L[0]을 추가해줍니다.
                L = L[1:]               #그리고 L[0]는 제거해주고 앞으로 한칸씩 당겨줍니다.
            else:                       #반대 라면
                result.append(R[0])     #결과값에 R[0]을 추가해줍니다.
                R = R[1:]               #그리고 R[0]는 제거해주고 앞으로 한칸씩 당겨줍니다.
        elif len(L) > 0:                #만약 L list에 값만 남았다면
            result.append(L[0])         #L list 자체는 sort가 되있으므로 
            L = L[1:]                   #결과값에 순서대로 넣어줍니다.   
        elif len(R) > 0:                #만약 R list에 값만 남았다면
            result.append(R[0])         #R list 자체는 sort가 되있으므로
            R = R[1:]                   #결과값에 순서대로 넣어줍니다.
    return result                       #최종 결과값을 minmax 함수로 이동시켜줍니다.


a = [4,5,2,3,6,8,1,7,9,90]
print(mergesort(a))