이전까지 배운 정렬 알고리즘은 성능이 좋지 않다.

병합 정렬은 이전에 배운 정렬 알고리즘(버블 정렬, 삽입 정렬, 선택 정렬)의 시간 복잡도 O(n²)를 O(n log n)까지 줄일 수 있다. 병합 정렬은 큰 배열을 더 작은 하위 배열로 나누어 정렬하는 분할 정복(Divide and Conquer) 패턴을 사용한 정렬 방법이다.

    [8, 2, 6, 3, 7, 1, 4, 9][8, 2, 6, 3] [7, 1, 4, 9][8, 2] [6, 3] [7, 1] [4, 9][8] [2] [6] [3] [7] [1] [4] [9][2, 8] [3, 6] [1, 7] [4, 9][2, 3, 6, 8] [1, 4, 7, 9][1, 2, 3, 4, 6, 7, 8, 9]

단일 요소를 가진 배열로만 이루어질 때까지 분할을 반복한다. 그리고 단일 요소로 이루어진 배열을 다시 정렬하며 병합한다. 그리고 정렬된 두 배열을 비교하여 마찬가지로 정렬된 형태로 병합한다. 그리고 모든 배열을 병합할 때까지 반복한다. 하나의 단계를 병합할 때는 시간복잡도가 그 단계의 숫자의 수, 즉 O(n)이 요구된다. n개의 숫자를 하나가 될 때까지 분할해 나가면 시간 복잡도는 O(log₂n)이 나온다.

즉, 이 패턴을 사용한 방식은 최고/최악 모두 O(n log n)이 나온다. 공간 복잡도도 O(n)으로 다른 정렬 방식(버블 정렬)보다 더 많은 공간을 요구한다.

/**
 *
 * @param {number[]} arr1
 * @param {number[]} arr2
 * @returns number[]
 */
function merge(arr1, arr2) {
  let answer = [];
  let i = 0;
  let j = 0;

  while (i < arr1.length && j < arr2.length) {
    if (arr1[i] < arr2[j]) {
      answer.push(arr1[i]);
      i++;
    } else {
      answer.push(arr2[j]);
      j++;
    }
  }

  while (i < arr1.length) {
    answer.push(arr1[i]);
    i++;
  }

  while (j < arr2.length) {
    answer.push(arr2[j]);
    j++;
  }

  return answer;
}

/**
 * @param {number[]} arr
 * @returns number[]
 */
function mergeSort(arr) {
  if (arr.length <= 1) return arr;

  let mid = Math.floor(arr.length / 2);
  let left = mergeSort(arr.slice(0, mid));
  let right = mergeSort(arr.slice(mid));

  return merge(left, right);
}

console.log(mergeSort([1, 53, 23, 92, 54, 111]));

0개의 댓글