defmerge_sort(arr,lt,rt): # 하나의 부분집합은 이미 정렬된 부분집합으로 보고 반환한다. if(lt>=rt): return #절반으로 부분집합을 나누어 각각에 대해 다시 재귀적으로 호출한다. mid = (lt+rt)//2; merge_sort(arr,lt,mid); merge_sort(arr,mid+1,rt);
p1 = lt; p2 = mid+1; #combine 과정 (정렬된 두개의 리스트를 합친다)
## 최적화 : arr[mid] 값이 arr[mid+1] 보다 작다면 이미 정렬되어있다는 의미므로 굳이 아래의 정렬과정을 반복할필요가없다. if(arr[mid] <= arr[mid+1]): return;
/*** * @param arr = 정렬할 배열 * @param lt = 분할 및 병합할 시작위치 * @param rt = 분할 및 병합할 마지막위치 * @param buff = 임시적으로 정렬된 결과를 담을 배열 */ publicstaticvoidmergeSort(int[] arr,int lt, int rt,int[] buff){
if(lt>=rt){ return; } int mid = (lt+rt)/2; // 1. divide mergeSort(arr,lt,mid,buff); mergeSort(arr,mid+1,rt,buff); int index = lt; int p1 = lt; int p2 = mid+1; if(arr[mid] <= arr[mid+1]){ return; } // 2. combine /*** * mid을 중심으로 2개의 정렬된 배열을 병합하는 과정 * p1(lt)가 p2(mid+1) 를 계속해서 비교해서 더 작은값을 임시배열에 삼입한다. * p2가 rt(병합할 배열의 마지막 위치)값을 넘은경우, p1에 남은 요소가 있으면 * 해당 값들을 임시배열에 삼입. 반대의 경우 (p1이 mid값을 넘은 경우)도 동일하게 * p2에 남은 요소가 있다면 해당 값들을 임시배열에 삼입 */ while(p1<=mid || p2<=rt) { if( p2 > rt || (p1<=mid && arr[p1]<arr[p2] )){ buff[index++] = arr[p1++]; } else{ buff[index++] = arr[p2++]; } } for(int i = lt ; i <= rt ; i++){ arr[i] = buff[i]; } } publicstaticvoidmain(String[] args){ int[] arr = {1,4,7,24,6,8,21,12,63}; /* 중간에 정렬결과를 저장할 buffer를 만든다. method안에서 buffer를 만들게 되면 계속해서 메모리 공간이 잡힘으로, 정렬전에 미리 공간을 할당하고, 정렬후에는 GC 대상이 되도록 null값을 할당한다. */ int[] buff = newint[arr.length]; System.out.println("Arrays.toString(arr) = " + Arrays.toString(arr)); mergeSort(arr,0,arr.length-1,buff); System.out.println("Arrays.toString(arr) = " + Arrays.toString(arr)); buff = null; } }
시간,공간복잡도
merge sort의 시간복잡도는 worst case에도 O(NlogN)의 시간복잡도를 가지며, 입력의 크기 만큼의 임시 버퍼를 만들어주어야 함으로, O(N)의 공간 복잡도를 가진다.