1
排序算法 平均情况 最好情况 最坏情况 辅助空间 稳定性
冒泡排序 O(n^2) O(n) O(n^2) O(1) 稳定
简单选择排序 O(n^2) O(n^2) O(n^2) O(1) 稳定
直接插入排序 O(n^2) O(n) O(n^2) O(1) 稳定
希尔排序 O(nlogn)~O(n^2) O(n^1.3) O(n^2) O(1) 不稳定
堆排序 O(nlogn) O(nlogn) O(nlogn) O(1) 不稳定
归并排序 O(nlogn) O(nlogn) O(nlogn) O(n) 稳定
快速排序 O(nlogn) O(nlogn) O(n^2) O(nlogn)~O(n) 不稳定

简单算法:冒泡、简单选择、直接插入
改进算法:希尔、堆、归并、快速

后三种改进算法比希尔算法效率高,但最好的情况下,冒泡和直接插入最有效,因此如果数组基本有序,则需要考虑简单算法

1. 冒泡排序

一、分析

  1. 冒泡arr.length-1趟;
  2. 第i趟,比较arr.length-i-1次,两两比较,反序则交换位置。

改进:为了避免已经有序的情况下进行无意义的两两比较,用flag标志上一趟是否有交换,没有交换则已经是有序数组,退出循环。

二、代码

    function bubbleSort(arr){
        var flag=true;
        for(let i=0;i<arr.length&&flag;i++){
            flag=false;
            for(let j=0;j<arr.length-i-1;j++){
                if(arr[j]>arr[j+1]){
                    [arr[j],arr[j+1]]=[arr[j+1],arr[j]];
                    flag=true;
                }
            }
        }
        return arr;
    }

2. 简单选择排序

一、分析

  1. 循环arr.length-1次,每一次的当前项与其之后的项作比较,找出其中最小的那个,与当前项交换。

二、代码

    function selectSort(arr){
        var min=0;
        for(let i=0;i<arr.length-1;i++){
            for(let j=i+1;j<arr.length;j++){
                if(arr[j]<arr[min]){
                    min=j;
                }
            }
            if(i!=min){
            [arr[i],arr[min]]=[arr[min],arr[i]];
            }
        }
        return arr;
    }

3. 直接插入排序

一、分析

  1. 从数组的第二项开始,循环arr.length-1次;
  2. 将当前项的值赋值给临时变量:(留出一个“坑”)为了前面大于当前项的项能够后移;
  3. 当前项与其前面的项比较,如果大于当前项后移,直到找到小于当前项的那个,将当前项插入其后;
  4. 如果前面没有小于当前项的,前面项全部后移以为,当前项就插入位置0处。

二、代码

    function insertSort(arr){
        for(let i=1;i<arr.length;i++){
            let temp=arr[i];
            let j=i-1;
            while(j>=0&&arr[j]>temp){
                arr[j+1]=arr[j];
                j--;
            }
            arr[j+1]=temp;
        }
        return arr;
    }

4. 希尔排序

  是一种改进版的插入排序,“缩小增量排序”。
一、分析

  1. 通过增量将待排序列分割成若干个子序列,每个子序列进行插入排序;
  2. 缩小增量,重复步骤1,直到增量不大于0;
  3. ps:增量等于1时,进行了一次全排的直接插入排序。这样做的目的是因为,直接插入排序在序列基本有序时效率最高。

二、代码

    function shellSort(arr){
        for(let increment=Math.floor(arr.length/2);increment>0;increment=Math.floor(increment/2)){
            for(let i=increment;i<arr.length;i++){
                let temp=arr[i];
                let j=i-increment;
                while(j>=0&&arr[j]>temp){
                    arr[j+increment]=arr[j];
                    j-=increment;
                }
                arr[j+increment]=temp;
            }
        }
        return arr;
    }

5. 堆排序

一、分析

  1. 将待排序列构造成一个大顶堆(位置0处,也就是堆顶,为最大数);
  2. 将arr[0]与arr[arr.length-1]进行交换,此时数组尾为最大值;
  3. 调整0~arr.length-2成一个大顶堆,继续2,直到全部排完。

二、代码

    function heapSort(arr){
        //1. 构造大顶堆
        //2. 顶值最大,交换到最末尾
        //3. 调整大顶堆
        var len=arr.length;
        for(let i=Math.floor(len/2)-1;i>=0;i--){
            heapAdjust(arr,i,len);
        }
        for(let i=arr.length-1;i>0;i--){
            [arr[0],arr[i]]=[arr[i],arr[0]];
            heapAdjust(arr,0,i);
        }
        return arr;
    }
    function heapAdjust(arr,pos,len){
        var root=pos;
        for(let i=2*pos+1;i<len;i=2*i+1){
            if(i+1<len&&arr[i]<arr[i+1]){
                i++;
            }
            if(arr[temp]<arr[i]){
                [arr[temp],arr[i]]=[arr[i],arr[temp]];
            }
            root=i;
        }
        // return arr;
    }

6. 归并排序

一、分析

  1. 将两个有序数组合成一个有序数组:归并。
  2. 将一个数组分割成长度为1的数组,就可以当做它是一个有序数组,两两合并,就成了一个长度为2的有序数组,再两两合并,直到排序完成。

二、代码

    function mergeSort(arr){
        if(arr.length<=1){return arr};

        let mid=Math.floor(arr.length/2);
        let left=arr.slice(0,mid);
        let right=arr.slice(mid);
        // console.log(left+"+"+right);
        return merge(mergeSort(left),mergeSort(right));
    }
    function merge(left,right){
        var result=[];
        while(left.length>0&&right.length>0){
            if(left[0]<right[0]){
                result.push(left.shift());
            }
            else{
                result.push(right.shift());
            }
        }
        return result.concat(left,right);
    }

7. 快速排序

一、分析

  1. 找基准
  2. 小于基准的放左边,大于基准的放右边;
  3. 递归基准左、右无序序列找基准;
  4. 直到输入数组长度为1,跳出递归。

二、代码

    function qSort1(arr){
        if(arr.length<=1){return arr;}

        let pivot=arr[0];
        let left=[];let right=[];
        for(let i=1;i<arr.length;i++){
            if(arr[i]<pivot){
                left.push(arr[i]);
            }
            else{
                right.push(arr[i]);
            }
        }
        return qSort1(left).concat(pivot,qSort1(right));
    }
    function qSort2(arr,low,high){
        if(low<high){
            var pivot=partition(arr,low,high);
            qSort2(arr,pivot+1,high);
            qSort2(arr,low,pivot-1);
        }
        // return arr;
    }
    function partition(arr,low,high){
        var pivot=arr[low];
        while(low<high){
            while(low<high&&pivot<=arr[high]){
                high--;
            }
            [arr[low],arr[high]]=[arr[high],arr[low]];
            while(low<high&&pivot>=arr[low]){
                low++
            }
            [arr[low],arr[high]]=[arr[high],arr[low]];
        }

        return low;
    }

candyCat
172 声望17 粉丝

未来可期,不断努力~