排序算法汇总

排序算法是一个最基本的算法,经常会被问到,有些公司的面试也可能会考到,这里特意将所有的排序算法做一个总结

1. 冒泡排序

    //冒泡排序,两个循环都从0开始冒泡
    public int[] MaoPao(int [] array){
        int len = array.length;
        for(int i=0;i<len-1;i++){
            for(int j=0;j<len-i-1;j++){
                if(array[j]>array[j+1]){
                    int temp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = temp;
                }
            }
        }
        return array;
    }

最基本的一个排序算法,总是将最大的往右进行冒泡,总是比较两个相邻的元素。

平均时间复杂度O(n^2),最好时间O(n),最坏时间O(n^2),空间复杂度O(1),不需要另外开辟空间

稳定的算法,因为冒泡排序总是比较相邻的两个元素,所以是稳定的。

 

2. 直接插入排序

    //直接插入排序
    public int[] ChaRu(int [] array){
        int len = array.length;
        for(int i=1;i<len;i++){
            int temp = array[i];
            int j=i-1;
            while(j>=0 && temp<array[j]){    //所有元素后移
                array[j+1]=array[j];
                j--;
            }
            array[j+1] = temp;     //出入元素
        }
        return array;
    }

第一个元素认为排序好的,之后的每一个元素往排好顺序的数组里插入,其他所有的元素向后移动一位

平均时间复杂度O(n^2),最好时间O(n),最坏时间O(n^2),空间复杂度O(1),不需要另外开辟空间

稳定的算法,因为出入排序每次也是相邻的比较并且后移,因此也是稳定的

 

3. 选择排序

    //选择排序,每次找到最小的排过去就好
    public int[] selectSort(int [] array){
        int len = array.length;
        for(int i=0;i<len;i++){
            int index = i;
            for(int j=len-1;j>i;j--){
                if(array[j]<array[index]){
                    index=j;
                }
            }
            int temp = array[i];
            array[i] = array[index];
            array[index] = temp;
        }
        return array;
    }

每次循环,找到最小的一个元素,放在每一次循环的位置

平均时间复杂度O(n^2),最好时间O(n^2),无论如何都需要循环完才能确定最小元素,最坏时间O(n^2),空间复杂度O(1),不需要另外开辟空间

不稳定的排序算法,因为每次都需要选择来进行,而且是选择位置插入的。

 

4. 快速排序

    //快速排序思想,每次第一个为base,然后小的放左边,大的放右边,递归两边
    public int[] quickSort(int[] array, int left, int right){
        if(left<right){
            int base = array[left];
            int temp;
            int i=left, j=right;
            do{
                while(array[i]<base && i<right){
                    i++;
                }
                while(array[j]>base && j>left){
                    j--;
                }
                if(i<=j){
                    temp = array[i];
                    array[i] = array[j];
                    array[j] = temp;
                    i++;
                    j--;
                }            
            }while(i<=j);
            if(left<j){
                quickSort(array,left,j);
            }
            if(right>i){
                quickSort(array,i,right);
            }
        }
        return array;
    }

每次,将首个left元素作为基础base,然后从left和right两边开始,小的放在左半部分,大的放在右半部分。然后递归排序左边和右边,直到left==right停止

平均时间复杂度O(nlog(n)),最好时间O(nlog(n)),最坏时间O(n^2),空间复杂度一般是O(log(n)),但是也可以到达O(1),如上述代码,是没有额外开辟空间的。

快速排序也是一个不稳定的排序算法

 

5. 归并排序

    //归并排序
    public int[] mergeSort(int[] array, int left, int right){
        int mid = (left+right)/2;
        if(left<right){
            mergeSort(array,left,mid);
            mergeSort(array,mid+1,right);
            merge(array,left,mid,right);
        }
        return array;
    }
    public void merge(int[] array, int left, int mid, int right){
        int[] temp = new int[right-left+1];
        int k = 0;
        int i=left;   //
        int j=mid+1;  ////合并
        while(i<=mid && j<=right){
            if(array[i]<array[j]){
                temp[k]=array[i];
                k++;
                i++;
            }else{
                temp[k]=array[j];
                i++;
                j++;
            }
        }
        //左边剩余
        while(i<=mid){
            temp[k]=array[i];
            k++;
            i++;
        }
        //右边剩余
        while(j<=right){
            temp[k]=array[j];
            k++;
            i++;
        }
        //复制到原数组中
        for(int ii=0;ii<temp.length;ii++){
            array[left+ii]=temp[ii];
        }
    }

采用了分治法的思想,首先把一个数组不断地拆分,一直拆分到每个都只有一个元素为止,然后调用merge算法,不断地合并两个已经排好序的数组,知道最后排好顺序

平均时间复杂度O(nlog(n)),最好时间O(nlog(n)),最坏时间O(nlog(n)),空间复杂度一般是O(log(n)),归并排序是需要额外的申请空间的,每次是需要生成新的数组的。

归并排序是稳定的,因为是总是先分治到最小的数组,然后进行合并的。

 

6. 希尔排序

本质是分治思想和直接插入排序算法的结合

平均时间复杂度O(n^(1.3)),最好时间O(n),最坏时间O(n^(2)),空间复杂度一般是O(1)

不稳定的排序算法

 

7. 堆排序

本质是使用最小堆或者最大堆进行排序(二叉树),首先需要建立堆,之后每次拿出一个最小元素或者最大元素,需要重新地调整堆

平均时间复杂度O(nlog(n)),最好时间O(nlog(n)),最坏时间O(nlog(n)),空间复杂度一般是O(l)

不稳定的排序算法

 

8. 基数排序,基于桶排序的算法

(1) 首先根据个位数进行桶排序,然后按照0-9得到桶中的元素

(2) 根据十位数进行桶排序,然后按照0-9得到桶中的元素

(3) .......

(4) 一直达到最高位位置,得到的结果即为最终的排序结果

 

9. 桶排序

用空间换取时间的做法,给定一个很大范围的桶,每个元素放在一个桶中,只用一遍循环便可

时间复杂度O(n)

 

总结

冒泡,插入,归并和基数排序都是稳定的排序算法

选择排序,快速排序,希尔排序和堆排序都是不稳定的排序算法

 

posted @ 2017-09-08 10:22  东木刀纹  阅读(150)  评论(0编辑  收藏  举报