排序算法之归并排序

120 阅读2分钟

这是我参与8月更文挑战的第18天,活动详情查看:8月更文挑战

归并排序

之前我们学到的冒泡排序、选择排序、插入排序因为性能不好的原因,而在实际的开发过程中几乎很少用到。而我们现在要准备学的归并排序性能不错,在实际开发中用的较多。

  • 归并排序:是一种分治算法。其思想是将原始数组切分成较小的数组,直到每个小数组只有一个位置,接着将小数组归并成较大的数组,直到最后只有一个排序完毕的大数组。
  • 归并排序 利用了 递归

实现

// 声明mergeSort方法,传入待排序数组
function mergeSort(arr) {
    // mergeSortRec是一个递归函数
    let arrTemp = mergeSortRec(arr)
    return arrTemp
}

// 实现 mergeSortRec方法
function mergeSortRec(arr) {
    let len = arr.length
    // 根据归并的核心思想,如果待排序数组长度为1,说明已经排好序了,直接返回
    if (len === 1) {
        return arr
    }
    // 找到数组的中间位置,将数组一分为二,分为左右两个数组,然后对切分之后的数组再分别进行二等分,一直递归到数组长度为1时结束
    let mid = Math.floor(len / 2);
    let left = arr.slice(0, mid)
    let right = arr.slice(mid, len)
    // merge方法用来将小数组排序并最终合并成大数组
    return merge(mergeSortRec(left), mergeSortRec(right))
}

// 实现merge函数,接收两个数组作为参数,并最终将其归并为一个大数组返回。
// 在归并的过程中进行排序
function merge(left, right) {
    // 定义变量 接收最终的数组
    let result = []
    // 左侧数组的循环起始点
    let il = 0;
    // 右侧数组的循环起始点
    let ir = 0;
    // 如果left数组中当前项,比right数组中的当前项小,那么将left数组中取出当前项,push到result数组中,并将当前迭代的i加1,否则将right数组中的当前项push到result中,同样的将迭代的i加1
    while (il < left.length && ir < right.length) {
        if (left[il] < right[ir]) {
            result.push(left[il++])
        } else {
            result.push(right[ir++])
        }
    } 
    // 左右两个数组都迭代完毕之后,分别将两个数组中剩余的元素,push到result数组中
    while (il < left.length) {
        result.push(left[il++])
    }
    while (ir < right.length) {
        result.push(right[ir++])
    }
    // 最后将结果数组返回
    return result
}

首先是将原始数组分割,直至只有一个元素的子数组,然后才开始归并。在归并的过程中完成排序。