# 归并排序

# 算法原理

归并排序是一种分治算法。其基本思想是将待排序序列分成若干个子序列,对每个子序列进行排序,然后再将已排序的子序列合并成一个有序序列。归并排序采用递归的方式,将大问题分解为小问题,然后逐步解决。

# 算法步骤

  1. 将长度为n的输入序列分成两个长度为n/2的子序列
  2. 对这两个子序列分别采用归并排序
  3. 将两个排序好的子序列合并成一个最终的排序序列

# 动图演示

比较次数: 0

交换次数: 0

# 代码实现

function mergeSort(arr) {
  const len = arr.length;
  if (len <= 1) return arr;
  
  // 分割数组
  const mid = Math.floor(len / 2);
  const left = arr.slice(0, mid);
  const right = arr.slice(mid);
  
  // 递归排序
  return merge(mergeSort(left), mergeSort(right));
}

function merge(left, right) {
  const result = [];
  let leftIndex = 0;
  let rightIndex = 0;
  
  // 比较左右数组的元素,将较小的元素放入结果数组
  while (leftIndex < left.length && rightIndex < right.length) {
    if (left[leftIndex] <= right[rightIndex]) {
      result.push(left[leftIndex]);
      leftIndex++;
    } else {
      result.push(right[rightIndex]);
      rightIndex++;
    }
  }
  
  // 将剩余元素添加到结果数组
  return result.concat(left.slice(leftIndex)).concat(right.slice(rightIndex));
}

# 复杂度分析

# 时间复杂度

  • 最好情况:O(n log n)
  • 最坏情况:O(n log n)
  • 平均情况:O(n log n)

# 空间复杂度

  • O(n),需要额外的数组空间来存储合并结果

# 算法特点

# 优点

  • 稳定排序
  • 时间复杂度稳定,不受输入数据的影响
  • 适合处理大规模数据
  • 可以轻松实现并行化

# 缺点

  • 需要额外的空间开销
  • 对于小规模数据,可能不如插入排序等简单排序算法
  • 递归调用会带来一定的函数调用开销

# 适用场景

  • 大规模数据排序
  • 要求稳定排序的场景
  • 外部排序(当数据量太大,无法一次性载入内存时)
  • 并行计算环境

# 优化方案

  1. 小规模数据使用插入排序:当子数组长度小于某个阈值时,使用插入排序
  2. 原地归并:减少空间开销
  3. 并行化处理:利用多线程进行子数组的排序
function optimizedMergeSort(arr) {
  const INSERTION_SORT_THRESHOLD = 10;
  
  function insertionSort(arr, left, right) {
    for (let i = left + 1; i <= right; i++) {
      const current = arr[i];
      let j = i - 1;
      
      while (j >= left && arr[j] > current) {
        arr[j + 1] = arr[j];
        j--;
      }
      
      arr[j + 1] = current;
    }
    return arr;
  }
  
  function sort(arr, temp, left, right) {
    // 小规模数据使用插入排序
    if (right - left <= INSERTION_SORT_THRESHOLD) {
      return insertionSort(arr, left, right);
    }
    
    const mid = Math.floor((left + right) / 2);
    
    // 递归排序
    sort(arr, temp, left, mid);
    sort(arr, temp, mid + 1, right);
    
    // 如果已经有序,则不需要合并
    if (arr[mid] <= arr[mid + 1]) {
      return arr;
    }
    
    // 合并两个有序数组
    merge(arr, temp, left, mid, right);
    
    return arr;
  }
  
  function merge(arr, temp, left, mid, right) {
    // 复制到临时数组
    for (let i = left; i <= right; i++) {
      temp[i] = arr[i];
    }
    
    let i = left;
    let j = mid + 1;
    let k = left;
    
    // 合并两个有序数组
    while (i <= mid && j <= right) {
      if (temp[i] <= temp[j]) {
        arr[k++] = temp[i++];
      } else {
        arr[k++] = temp[j++];
      }
    }
    
    // 复制剩余元素
    while (i <= mid) {
      arr[k++] = temp[i++];
    }
  }
  
  const temp = new Array(arr.length);
  return sort(arr, temp, 0, arr.length - 1);
}