LearnApplyShare

[알고리즘] Merge sort

September 02, 2018 - [algorithm, merge-sort]

정렬된 2개의 배열이 주어 진다면 정렬상태를 유지하며 병합하는 것은 참 쉽다. 이 점에 착안하여 임의의 주어진 배열을 가운데 기준으로 양분한 뒤 정렬된 상태를 유지하며 다시 병합하는 방법. 나뉘어진 두 부분의 배열에 대해서도 재귀적으로 병합정렬을 수행.

한줄요약,

2개로 나누고 정렬된 2개의 배열을 병합. 나누어진 배열에 재귀호출


특징

  • 분할&정복
  • 시간복잡도: O(nLogn)
  • 공간복잡도: O(n)
  • 안정정렬

js코드

function merge(arr1, arr2) {
  var res = []
  while (arr1.length > 0 || arr2.length > 0) {
    if (arr1.length === 0) {
      res.push(arr2.shift())
    } else if (arr2.length === 0) {
      res.push(arr1.shift())
    } else if (arr1[0] <= arr2[0]) {
      // 여기서 = 를 빼면 불안정정렬이 된다
      res.push(arr1.shift())
    } else {
      res.push(arr2.shift())
    }
  }
  return res
}

function mergeSort(arr) {
  if (arr.length <= 1) {
    return arr // 배열의 길이가 0 or 1이면 정렬된 상태로 간주하고 그대로 리턴
  }
  var pivot = Math.floor(arr.length / 2)
  var left = arr.slice(0, pivot)
  var right = arr.slice(pivot, arr.length)
  return merge(mergeSort(left), mergeSort(right))
}

var arr = [7, 4, 9, 8, 5, 3, 2, 1, 9, 3]
// mergeSort는 arr의 상태는 변화시키지 않고 정렬된 새로운 배열을 리턴함
mergeSort(arr) // [1, 2, 3, 3, 4, 5, 7, 8, 9, 9]

재귀 대신 루프 사용도 가능

배열을 한방에 잘개 분할하고 루프를 이용해 한꺼번에 병합하는 것도 가능

function merge(arr1, arr2) {
  if (arr1 === undefined || arr2 === undefined) {
    // 아래 mergeSort 의 인자로 주어지는 배열 arr의 길이가 홀수인 경우, 루프 안에서 chunks[i+1] 의 인덱스가 배열의 길이를 오버하여 arr2가 undefined 로 들어올 수 있다
    return arr1 || arr2
  }
  var res = []
  while (arr1.length > 0 || arr2.length > 0) {
    if (arr1.length === 0) {
      res.push(arr2.shift())
    } else if (arr2.length === 0) {
      res.push(arr1.shift())
    } else if (arr1[0] <= arr2[0]) {
      // 여기서 = 를 빼면 불안정정렬이 된다
      res.push(arr1.shift())
    } else {
      res.push(arr2.shift())
    }
  }
  return res
}

function mergeSort(arr) {
  if (arr.length <= 1) {
    return arr
  }
  var chunks = arr.map(v => [v])
  while (chunks.length > 1) {
    var newChunks = []
    for (var i = 0; i < chunks.length; i += 2) {
      newChunks.push(merge(chunks[i], chunks[i + 1]))
    }
    chunks = newChunks
  }
  return chunks.pop()
}

var arr = [7, 4, 9, 8, 5, 3, 2, 1, 9, 3]
// mergeSort는 arr의 상태는 변화시키지 않고 정렬된 새로운 배열을 리턴함
mergeSort(arr) // [1, 2, 3, 3, 4, 5, 7, 8, 9, 9]