Fork me on GitHub

JavaScript实现归并排序

JavaScript实现归并排序

参考文章

归并排序就这么简单---文章通俗易懂,加深理解

过程描述

归并过程为:比较a[i]和b[j]的大小,若a[i]≤b[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素b[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。

代码实现

根据参考文章,仅做语言上的修改变更,后文有代码简化版

/**
 * 归并排序
 * @param {Array} arrays 
 * @param {Number} L 数组第一个元素
 * @param {Number} R 数组最后一个元素
 */
function mergeSort(arrays, l, r) {
    if (l === r) {
        return;
    } else {
        // 取中间的数,进行拆分
        const m = Math.floor((l + r) / 2);

        //左边不断进行拆分
        mergeSort(arrays, l, m);
        //右边不断进行拆分
        mergeSort(arrays, m + 1, r);
        //合并
        merge(arrays, l, m + 1, r);

    }
}


/**
 * 合并数组
 * @param {Array} arrays 
 * @param {Number} l 数组第一个元素
 * @param {Number} m 数组分割元素
 * @param {Number} r 数组最后一个元素
 */
function merge(arrays, l, m, r) {
    let leftArr = new Array(m - l),//左边数组大小
        rightArr = new Array(r - m + 1);//右边数组大小

    //往数组中填充数据
    for (let i = l; i < m; i++) {
        leftArr[i - l] = arrays[i];
    }
    for (let i = m; i <= r; i++) {
        rightArr[i - m] = arrays[i];
    }

    let i = 0, j = 0, k = l;

    //比较这两个数组的值,哪个小就往数组上放
    while (i < leftArr.length && j < rightArr.length) {
        if (leftArr[i] < rightArr[j]) {
            arrays[k] = leftArr[i];
            k++;
            i++;
        } else {
            arrays[k] = rightArr[j];
            k++;
            j++;
        }
    }

    //如果左边的数组没读完,那么把剩余的都直接填充到后面
    while (i < leftArr.length) {
        arrays[k] = leftArr[i];
        k++;
        i++;
    }

    // //如果右边的数组没读完,那么把剩余的直接填充都后面
    while (j < rightArr.length) {
        arrays[k] = rightArr[j];
        k++;
        j++;
    }
}

//测试demo
let originArr = [9, 2, 5, 1, 3, 2, 9, 5, 2, 1, 8];
mergeSort(originArr, 0, originArr.length - 1);
console.log(originArr);//[1, 1, 2, 2, 2, 3, 5, 5, 8, 9, 9]

简化代码的实现

/**
 * 归并排序
 * @param {Array} arrays 
 * @param {Number} L 数组第一个元素
 * @param {Number} R 数组最后一个元素
 */
function mergeSort(arrays, l, r) {
    if (l === r) {
        return;
    } else {
        // 取中间的数,进行拆分
        const m = Math.floor((l + r) / 2);
        //左边不断进行拆分
        mergeSort(arrays, l, m);
        //右边不断进行拆分
        mergeSort(arrays, m + 1, r);
        //合并
        merge(arrays, l, m + 1, r);
    }
}


/**
 * 合并数组
 * @param {Array} arrays 
 * @param {Number} l 数组第一个元素
 * @param {Number} m 数组分割元素
 * @param {Number} r 数组最后一个元素
 */
function merge(arrays, l, m, r) {
    let leftArr = arrays.slice(l, m),//左边数组
        rightArr = arrays.slice(m, r + 1);//右边数组

    let i = 0, j = 0, k = l;

    //比较这两个数组的值,哪个小就往数组上放
    while (i < leftArr.length && j < rightArr.length) {
        arrays[k++] = leftArr[i] < rightArr[j] ? leftArr[i++] : rightArr[j++];
    }

    //如果左边的数组没读完,那么把剩余的都直接填充到后面
    while (i < leftArr.length) {
        arrays[k++] = leftArr[i++];
    }

    //如果右边的数组没读完,那么把剩余的直接填充都后面
    while (j < rightArr.length) {
        arrays[k++] = rightArr[j++];
    }
}
let originArr = [9, 2, 5, 1, 3, 2, 9, 5, 2, 1, 8];
mergeSort(originArr, 0, originArr.length - 1);
console.log(originArr);

posted @ 2019-08-15 11:36  粥里有勺糖  阅读(285)  评论(0编辑  收藏  举报