排序

1.交换排序

1.1冒泡排序

冒泡排序的时间复杂度是O(n^2)。基本思路是,未排序元素两两比较并交换,选出最大(小)的元素放到已排序元素区的头部。

冒泡排序有两个可以优化的点:

1)在某轮排序中,如果一次交换都没有发生,说明序列已经排好序,可以直接退出排序了;

2)在某轮排序中,如果某次交换后(设交换发生在array[boundIndex]和array[boundIndex+1]),后面的一系列比较都没有发生交换,则说明下标大于boundIndex的元素都排好序了,下轮排序只需要排下标为0-boundIndex的元素。

 

1.2快速排序

快速排序的时间复杂度为O(nlogn)。因为每轮比较都需要遍历n个元素,比较的总轮数是logn(n/2^{logn}=1)。

快速排序每一轮的步骤是:

1)选出数组的第一个元素为pivot,第二个元素为leftPointer,最后一个元素为rightPointer;

2)两个指针依次向中间遍历,如果rightPointer发现异常的元素(小于等于pivot)指针就停下来,和另一个指针发现的异常元素(大于pivot)进行交换。

3)当两个指针指向同一个元素,遍历结束。将pivot设置为两个指针指向的同一个元素,然后递归排序pivot左边的元素和右边的元素,重复步骤1)。

 

1.3堆排序

1)将数组重整为一个二叉堆。如果需要升序就重整成最大二叉堆,需要降序就重整成最小二叉堆;

2)堆顶元素和二叉堆的最后一个元素交换位置,同时对二叉堆进行下降操作(下降范围不包括原来的堆顶元素)。

3)重复2)N-1次。

 

2.计数排序

计数排序的时间复杂度是O(n),具体步骤分以下4个:

1)找出数组array的最大值max和最小值min;

2)创建一个统计数组countArray,countArray的长度为max-min+1,countArray[i]存储array中的满足value-min=i的元素;

3)将countArray的第i(i>=2)个元素依次重新赋值为第i-1个元素值+第i个元素值。完成这个步骤之后,countArray[i]-1就代表了array中满足value-min=i的最后一个元素在排好序的数组中存放的下标。

4)从后往前遍历array(这是保证稳定排序的关键),countArray[array[i]-min]-1就代表array[i]在sortedArray中的下标。

计数排序虽然时间复杂度很低,但是应用的很少,因为它在以下两个场景中无法使用:

1)当原始数组的排布过于稀疏,例如:原始数组总共100个元素,但最大值为一百万,最小值却只有1。这时如果用计数排序,将浪费大量空间,而且也很耗时;

2)当原始数组的元素不是整数。

public class CountSort {
    public int[] countSort(int[] array){
        //1.先求出原始数组的最大值和最小值
        int max = array[0];
        int min = array[0];
        int len = array.length;
        for(int i=1;i<len;i++){
            if(array[i]>max){
                max = array[i];
            }
            if(array[i]<min){
                min = array[i];
            }
        }
        //2.计算countArray的元素值
        int[] countArray = new int[max-min+1];
        for(int i=0;i<len;i++){
            countArray[array[i]-min]++;
        }
        //3.将countArray中的元素值变为原始数组中元素在排序后的位次
        for(int i=1;i<(max-min+1);i++){
            countArray[i] += countArray[i-1];
        }
        //4.将原始数组中的值放到它应该去的位置,注意从后往前遍历是保证稳定排序的关键
        int[] sortedArray = new int[len];
        for(int i=len-1;i>=0;i--){
            sortedArray[countArray[array[i]-min]-1] = array[i];
            countArray[array[i]-min]--;
        }

        return sortedArray;
    }
}

 

 

3. 桶排序

桶排序是为了解决计数排序不能处理非整数序列的缺点。桶排序的时间复杂度为O(n),具体步骤如下:

1)设置一个arrayList,元素类型为链表,这个arrayList的长度为原始数组的长度。arrayList的最后一个桶只存放最大值;

2)获取原始数组的最大值max和最小值min,求除最后一个桶之外的其他桶的区间长度:d=(max-min)/(arrayList.lenth-1);

3)遍历原始数组array,将array[i]存放进第(array[i]-min)/d+1个桶;

4)对每个桶进行归并排序,时间复杂度为O(nlogn);

5)从前往后依次遍历每个桶,得到升序数组,也可以从后往前依次遍历每个桶,得到降序数组。

 

posted @ 2020-10-02 12:11  日进一卒  阅读(202)  评论(0)    收藏  举报