Javascript排序算法上篇(冒泡排序,选择排序,插入排序,归并排序)

284 阅读3分钟

冒泡排序


冒泡排序比较任何两个相邻的项,如果第一个比第二个大,则交换它们。元素项向上移动到正确的顺序,就好像气泡升至表面一样,冒泡排序因此得名。

基本的冒泡排序

function bubbleSort(arr){
    let length = arr.length;
    // 交换函数
    function swap(arr, index1, index2){
        let item = arr[index1];
        arr[index1] = arr[index2];
        arr[index2] = item;
        //ES6中可写为   [arr[index1],arr[index2]] = [arr[index2],arr[index1]]
    }
    for(let i = 0; i < length; i++){
        for(let j = 0; j < length-1; j++){
            if(arr[j] > arr[j+1]){
                swap(arr, j, j+1);
            }
        }
    }
    return arr;
}

第一次外循环确定了最后一个值,第二次外循环确定了倒数第二个值,第三次外循环确定了倒数第三个值.....依此类推。

改进后的冒泡排序

function bubbleSort(arr){
    let length = arr.length;
    // 交换函数
    function swap(arr, index1, index2){
        let item = arr[index1];
        arr[index1] = arr[index2];
        arr[index2] = item;
    }
    for(let i = 0; i < length; i++){
        //内循环中减去外循环中已跑过的轮数,避免不必要的比较
        for(let j = 0; j < length-1-i; j++){ 
            if(arr[j] > arr[j+1]){
                swap(arr, j, j+1);
            }
        }
    }
    return arr;
}

每次外循环都确定一个值的位置,所以没必要在内循环中每次都循环(length-1)次,而是改为(length-1-i)

选择排序


选择排序是找到数组中的最小值放到第一位,接着找到第二小的值并将其放到第二位,依此类推。

function selectSort(arr){
    let length = arr.length;
    let minIndex; //最小值的下标
    // 交换函数
    function swap(arr, index1, index2){
        [arr[index1],arr[index2]] = [arr[index2],arr[index1]]
    }
    for(let i = 0; i < length-1; i++){
        minIndex = i;//第一次循环放第一个位置,第二次循环放第二个位置...
        for(let j = i; j < length; j++){
            if(arr[minIndex] > arr[j]){
                minIndex = j; //找到最小值的下标
            }
        }
        if(i !== minIndex){ //如果找到的最小值下标不等于i
            swap(arr, i, minIndex) //交换位置
        }
    }
    return arr;
}

插入排序


假设第一项已经排序了,接着让第二项和他比较,决定第二项排在第一项之前还是之后,这样头两项就排好了,然后用第三项和前两项比较,确定前三项的顺序,依此类推。

function insertionSort(arr){
    let length = arr.length;
    let j = 0;
    let temp = 0;
    for(let i = 1; i < length; i++){
        j = i; //避免死循环,所以用j代理i做内循环
        temp = arr[i];
        while(j > 0 && arr[j-1] > temp){
            arr[j] = arr[j-1];
            j--;
        }
        arr[j] = temp;
    }
    return arr;
}

此算法比选择排序和冒泡排序性能要好,但是没有下面几个性能好

归并排序


归并排序是一种分治算法,思路是将原始数组切分成较小的数组,直到每个小数组只有一个元素,接着将小数组排序归并成较大的数组,直到最后只有一个排序完毕的大数组。

let merge = function(left,right){
    let result = [];
    let il = 0;
    let ir = 0;
    while(il < left.length && ir < right.length){
        if(left[il]<right[ir]){
            result.push(left[il++]);
        }else{
            result.push(right[ir++]);
        }
    }
    while(il<left.length){
        result.push(left[il++]);
    }
    while(ir<right.length){
        result.push(right[ir++]);
    }
    return result;
}
let mergeSortRec = function(arr){
    let length = arr.length;
    //一直分到数组长度为1,直接返回该数组
    if(length === 1){
        return arr;
    }
    let mid = Math.floor(length/2);
    let left = arr.slice(0,mid);
    let right = arr.slice(mid,length);
    return merge(mergeSortRec(left),mergeSortRec(right));//递归
}

其中mergeSortRec函数把数组转化为多个小数组直到只有一个项,merge函数合并排序小数组最后回到原始数组。merge函数可以把任意两个有序数组进行合并为一个有序数组。例如:

merge([1,7,11],[2,3,5,8,13])   //[1,2,3,5,7,8,11,13]