归并排序

归并排序

June 3, 2022
sort

实现 #

归并排序,采用分治法,时间复杂度为 \(O(nlog n)\)


/**
 * @param {number[]} arr 待合并原始数组
 * @param {number} p 左索引,第一个元素的索引
 * @param {number} q 中位索引
 * @param {number} r 右索引,最后一个元素的索引
 *
 * [p, q), [q, r] 均为已排序好的子数组
 *
 * 将 [p,q), [q, r] 合并为一个排序好的数组
 *
 */
const merge = (arr, p, q, r) => {
  // concat 的为哨兵节点
  const arrLeft = arr.slice(p, q + 1).concat(Number.POSITIVE_INFINITY);
  const arrRight = arr.slice(q + 1, r + 1).concat(Number.POSITIVE_INFINITY);

  let indexL = 0;
  let indexR = 0;

  // 注意,遍历从 p 开始,到 r+1
  for (let i = p; i < r + 1; i++) {
    if (arrLeft[indexL] < arrRight[indexR]) {
      arr[i] = arrLeft[indexL];
      indexL++;
    } else {
      arr[i] = arrRight[indexR];
      indexR++;
    }
  }
};

/**
 * 归并排序
 * @param {number[]} arr 待排序数组
 * @param {number} p 左索引 第一个元素的索引
 * @param {number} r 右索引 最后一个元素的索引
 *
 * 思路: 将大数组按中位索引依次拆为更小的两个子数组,将两个子数组排序,然后合并两个排序好的子数组
 *
 * 注意:当拆到最后子数组只有一个元素时,默认为已排序好的,此为递归的终止条件
 */
const mergeSort = (arr, p, r) => {
  if (p < r) {
    let median = Math.floor((p + r) / 2);
    // 排序左数组
    mergeSort(arr, p, median);

    // 排序右数组
    mergeSort(arr, median + 1, r);

    // 合并两个排序好的子数组
    merge(arr, p, median, r);
    // console.log("arr", arr);
  }
  return arr;
};

export { mergeSort };

const arr = [5, 2, 4, 7, 1, 3, 2];
console.log("merge", mergeSort(arr, 0, arr.length - 1));

分析 #