public class MergeSort {
public static void main(String[] args) {
int[] arr = { 29, 10, 14, 37, 13 };
mergeSort(arr, 0, arr.length - 1);
for (int i : arr) {
System.out.print(i + " ");
}
}
public static void mergeSort(int[] arr, int left, int right) {
if (left < right) {
int mid = (left + right) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
}
public static void merge(int[] arr, int left, int mid, int right) {
int[] temp = new int[arr.length];
int i = left;
int j = mid + 1;
int k = left;
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
while (i <= mid) {
temp[k++] = arr[i++];
}
while (j <= right) {
temp[k++] = arr[j++];
}
for (int index = left; index < k; index++) {
arr[index] = temp[index];
}
}
}
public static void mergeSort(int[] arr, int left, int right) {
if (left < right) {
int mid = (left + right) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
}
public static void mergeSort(int[] arr, int left, int right)
함수의 매개변수 : 정렬할 배열(arr)과 배열의 시작 인덱스(left)와 끝 인덱스(right)
if (left < right)
함수의 시작 부분에서는 배열을 반으로 나누기 위한 조건을 확인
int mid = (left + right) / 2;
배열의 중간 인덱스(mid)를 계산
mergeSort(arr, left, mid);
배열의 왼쪽 부분을 정렬하기 위해 mergeSort() 함수를 재귀적으로 호출
mergeSort(arr, mid + 1, right);
배열의 오른쪽 부분을 정렬하기 위해 mergeSort() 함수를 재귀적으로 호출
merge(arr, left, mid, right);
왼쪽과 오른쪽 부분을 정렬한 후, 두 부분을 병합
public static void merge(int[] arr, int left, int mid, int right) {
int[] temp = new int[arr.length];
int i = left;
int j = mid + 1;
int k = left;
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
while (i <= mid) {
temp[k++] = arr[i++];
}
while (j <= right) {
temp[k++] = arr[j++];
}
for (int index = left; index < k; index++) {
arr[index] = temp[index];
}
}
머지하는 부분
int[] temp = new int[arr.length];
먼저, 정렬된 배열을 저장할 임시 배열 temp를 생성
int i = left;
int j = mid + 1;
int k = left;
왼쪽 부분의 시작 인덱스 i, 오른쪽 부분의 시작 인덱스 j, 그리고 정렬된 배열의 시작 인덱스 k를 각각 left, mid+1, left로 초기화
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
while 문을 사용하여 왼쪽 부분과 오른쪽 부분의 원소를 비교하고 작은 원소부터 temp 배열에 저장
while (i <= mid) {
temp[k++] = arr[i++];
}
while (j <= right) {
temp[k++] = arr[j++];
}
위의 while문이 종료되면 왼쪽 부분이나 오른쪽 부분 중 하나는 남은 원소가 있을 수 있다.
for (int index = left; index < k; index++) {
arr[index] = temp[index];
}
마지막으로, temp 배열의 값을 arr 배열에 복사
나무위키의 설명
성능은 아래의 퀵 정렬보다 전반적으로 뒤떨어지고, 데이터 크기만한 메모리가 더 필요하지만 '최대의 장점은 데이터의 상태에 별 영향을 받지 않는다는 점'이다.
힙이나 퀵의 경우에는 배열 A[25]=100, A[33]=100인 정수형 배열을 정렬한다고 할 때, 33번째에 있던 100이 25번째에 있던 100보다 앞으로 오는 경우가 생길 수 있다.
그에 반해서 병합정렬은 이런 일이 발생하지 않는다. 기본적으로 병합정렬은 쪼갠 후 두 값을 비교할 때 값이 같으면 정렬하지 않게 설계되기 때문이다.
그게 뭐가 중요하냐고 할 수 있지만, 실제 상황에서 여러 기준으로 정렬했을 때 동일 값에 대해선 기존 기준의 정렬순서가 유지되어야 한다.
예를 들어 동점일 경우 생년월일 기준으로 수상자를 뽑는 규정이 있는 대회에서 참가자들을 생년월일 순서대로 정렬해놓고 시험점수 기준으로 다시 정렬할 경우, 병합 정렬은 동점자들끼리 생년월일 순서대로 정렬된 것이 100% 유지된다.
정렬되어 있는 두 배열을 합집합할 때 이 알고리즘의 마지막 단계만을 이용하면 가장 빠르게 정렬된 상태로 합칠 수 있다.
장점
단점