经典排序——快排及三种优化

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/L_0000/article/details/82428206

经典排序——快排及三种优化

快排时间复杂度为O(nlogn)~O(n^2),不稳定排序
废话不多说,直接上代码:

public class Main{
    public static void main(String[] args){
        //产生随机数作为测试数据,[0,100)的10个随机数
        int[] arr = generateData(0,100,10);
        //打印排序前的数组
        for(int i:arr){
            System.out.print(i + " ");
        }
        quickSort(arr);
        //打印排序后的数组
        System.out.println();//打印一个换行
        for(int i:arr){
            System.out.print(i + " ");
        }
    }
    //经典快排:
    public static void quickSort(int[] arr){
        int left = 0;
        int right = arr.length-1;
        sort(arr,left,right);
    }
    public static void sort(int[] arr,int left,int right){
        if(left >= right)
            return ;
        //使用pivot,使arr[left,...,pivot-1]< arr[pivot],arr[pivot+1,...,right]>arr[pivot]
        int pivot = partition(arr,left,right);
        sort(arr,left,pivot-1);//对小于的部分进行排序
        sort(arr,pivot+1,right);//对大于的部分进行排序
    }
    public static int partition(int[] arr,int l,int r) {
        //返回part,使arr[l+1,..j]<v,arr[j+1,...i]>v 
        int pivot = arr[l];
        while(l<r) {
            while(l<r && arr[r]>=pivot) {
                r--;
            }
            swap(arr,l,r);
            while(l<r && arr[l]<=pivot) { 
                l++;
            }
            swap(arr,l,r);
        }
        return l;
    }
}
//产生随机数组,范围是[start,num)的num个随机数据
public static int[] generateData(int start,int end,int num){
    int[] arr = new int[num];
    Random random = new Random();
    for(int i = 0; i < num; i++){
        //先使用random.nextInt(n),产生[0,n-1)的随机数,再加上start
        arr[i] = random.nextInt(end-start) + start;
    }
    return arr;
} 
//数据交换
public static void swap(int[] arr,int i,int j){
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

优化1——优化pivot的选择

在经典中pivot的选值是固定选取某一位置(如第一位置),以极端情况为例,若选择了最小数,或最大数,此时的时间复杂度就比较高,这有时不合理。
对于小数组使用三数取中,大数组使用九数取中

int pivot
int mid = low + (high - low)/2;
if(arr[low] > arr[high])//保证左端最小
    swap(arr,low,high);
if(arr[mid] > arr[high])//保证中间最小
    swap(arr,mid,high);
if(arr[mid] < arr[low])//保证左端最小
    swap(arr,mid,low);
pivot = arr[low];

优化2——优化不必要的交换

在经典快排的partition中有些交换是不必要的,我们可以使用赋值代替交换
保存最初的比较数,对于原来需要交换的位置直接赋值,最后取回比较数放到 L 的位置即可
代码如下:

public static int partition(int[] arr,int l,int r) {
        public static int partition(int[] arr,int l,int r) {
        int pivot = arr[l];
        while(l<r) {
            while(l<r && arr[r]>=pivot) {
                r--;
            }
            //swap(arr,l,r);
            arr[l] = arr[r];//小的放前
            while(l<r && arr[l]<=pivot) { 
                l++;
            }
            //swap(arr,l,r);
            arr[r] = arr[l];//大的放后
        }
        arr[l] = pivot;//最后l和r在中间相遇,此时 将pivot放到arr[l],而此时的l即为分界位置,返回l
        return l;
    }

优化3——小数组时,直接使用插入排序更快

代码,后面再加

猜你喜欢

转载自blog.csdn.net/L_0000/article/details/82428206