JavaScript 数据结构与算法——归并排序

118 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第 5 天,点击查看活动详情

介绍

归并排序就是将两个或两个以上的有序表合并成一个有序表的过程。将两个有序表合并成一个有序表的过程称为 2-路归并,2-路归并,最为简单常用。

思路

假设初始序列含有 n 个记录,则可看成 n 个有序的子序列,每个子序列的长度为 1,然后两两归并,得到[n/2]个长度为 2 或 1 的有序子序列,再两两归并,....,如此重复,直至得到一个长度为 n 的有序序列为止。

归并排序

实现

/**
 * 归并排序就是将两个或两个以上的有序表合并成一个有序表的过程。将两个有序表合并成一个有序表的过程称为2-路归并,2-路归并,最为简单常用,
 */

/**
 *
 * @param array 需要排序的数组
 * @param compar 比较函数
 * @returns 返回排序好的数组
 */
function mergeSort<T>(array: T[], compar: (left: T, right: T) => number): T[] {
  let temp: T[];
  //如果数组长度大于1,那么就对它进行归并排序
  if (array.length > 1) {
    const middle: number = Math.floor(array.length / 2);
    const left: T[] = mergeSort(array.slice(0, middle), compar);
    const right: T[] = mergeSort(array.slice(middle, array.length), compar);

    temp = merge<T>(left, right, compar);
    return temp;
  }

  //数组长度小于等于1,直接返回单个数组进行归并
  return array.slice(0);
}

/**
 *
 * @param left 第一个元素
 * @param right 第二个元素
 * @param compar 比较函数
 * @returns 返回一个排序好的数组
 */
function merge<T>(
  left: T[],
  right: T[],
  compar: (left: T, right: T) => number
): T[] {
  //存储排序好的数组
  let temp: T[] = [];

  let i: number = 0;
  let j: number = 0;
  let k: number = 0;

  //进行遍历
  while (i < left.length && j < right.length) {
    //进行比较
    if (compar(left[i], right[j]) === -1) {
      //把left数组的值放到temp数组
      temp[k] = left[i];
      i++;
    } else {
      //把right数组的值放到temp当中
      temp[k] = right[j];
      j++;
    }
    k++;
  }

  //如果最后,left数组当中还存在元素,那么我们直接将他放到temp数组的后面
  while (i < left.length) {
    temp[k] = left[i];
    k++;
    i++;
  }

  //如果最后,right数组当中还存在元素,那么我们直接将他放到temp数组的后面
  while (j < right.length) {
    temp[k] = right[j];
    k++;
    j++;
  }

  //返回排序好的数组
  return temp;
}

/**
 *
 * @param left 左边数组的元素
 * @param right 右边数组的元素
 * @returns 返回比较结构 大于 1 小于 -1
 */
function compar<T>(left: T, right: T): number {
  if (left > right) {
    return 1;
  } else {
    return -1;
  }
}

const array: number[] = [1, 5, 7, 9, 4, 2, 45, 12, 39, 78, 14, 23];
const result: number[] = mergeSort<number>(array, compar);

console.log(result);

上面的代码当中,我们首先创建一个mergeSort函数,函数接收两个参数arraycompar,array是我们需要排序的数组compar是我们传入进去的比较函数。我们可以灵活的比较两个数值的大小。进入函数,如果数组的长度小于 1,直接返回数组,因为单个元素我们可以看成已经拍好了序,当数组大于 1,我们先将数组分成两份,leftright。分成两份后,我们使用递归,不断的将数组分成两份,直到数组当中只包含一个元素。由此我们就可以将leftright两个数组进行比较,因为这时候两个数组当中都只包含一个元素。我们使用merge函数进行归并。在merge当中,我们首先使用 while 循环来比较两个数组当中小的那一个,放入我们准备好的temp当中,另外一个,比较ileft.length(或jright.leng),如果 i 比 left.lenght 小那么直接将 left 当中的元素放入temp当中,反之亦然。最后返回归并好的数组。