• 快速排序(三向切分快速排序)


    快速排序(交换排序,递归操作)

    • 思路:

      • 快速排序核心思想是找一个基点,然后让基点左右两遍元素依次和它比较,如果左边某个元素大于基点且右边某个小于基点,则将这俩交换;直到左右两边到达基点,越位之后开始递归,总体分为两部分一左一右,而一左一右之中又可以分为一左一右,这样递归下去,直到两端为止。这个过程类似一生二、二生四、四生八......
      • 这里可以看出快速排序是不稳定的
        (假设,左边第一个数大于基数,最右边有两个相同的数都小于基数,于是,左边的数先和右边后一个数交换,之后如果左边的第二个数仍然大于基数,那么再次进行交换后,两个相同的数的相对位置就发生了改变)

    以下用一个图例说明快速排序过程,这里给出一组测试数组:-9,78,0,23,-56,70;图中pivot表示基准,假设基准=(0+5)/2=2

    '一生二' 步骤如下:

    递归开始

    具体代码

    public static void quickSort(int[] nums, int left, int right) {
    		int pivot = nums[(left + right) / 2];//基准找的中间的
    		int l = left;//基准左边的
    		int r = right;//基准右边
    		int temp = 0;//用于交换的临时变量
    		while (l < r) {//当索引下标基准左边的小于右边的,说明基准两边的值需要排序
    			while (nums[l] < pivot)//基准左边的值小于基准时,则不用交换,继续比较下一个,当基准左边的某个值大于基准时,跳出循环,此时l为需要交换的元素下标
    				l++;
    			while (nums[r] > pivot)//同理,同上
    				r--;
    			if (l == r)//如果当基准左右索引相等时,则退出当前循环,主要是(为了避免同一索引位置的交换)。
    				break;
    			temp = nums[l];
    			nums[l] = nums[r];
    			nums[r] = temp;
    			if (nums[l] == pivot)//为了避免重复执行上面两个while语句,(当只有两个元素进行比较交换后,那么就应该退出本次循环)
    				r--;
    			if (nums[r] == pivot)//同理,同上
    				l++;
    			 System.out.println(Arrays.toString(nums));
    		}
    		r--;//上面的循环执行结束后,基准左小右大成立
    		l++;//必然l==r==pivot的下标,所以进行r--和l++是为了给左右递归做准备!
    		if (left < r)//当基准左边第一个r的索引大于0时,那么说明基准左边起码有≥2个值,需要再进行排序
    			quickSort(nums, left, r);//左递归
    		if (l < right)//同理,同上
    			quickSort(nums, l, right);//有递归
    	}
    
    

    测试

    before:2020/02/13 20:39:07:910
    after:2020/02/13 20:39:09:310
    800w数据(数据区间在0——1000w)排序:花了大概不到2s
    时间复杂度:最坏情况:O(n^2) 最好情况:O(nlogn)

    三向切分的快速排序(改进快排之一)

    它的出现是对含有以任意概率分布的重复元素的输入进行优化。
    基准为左边第一个元素,lt初始位置也是最左边,有一个索引i从基准右边开始遍历,如果发现nums[i]<基准,则进行交换并将lt和i加一;否则如果nums[i]>基准,那么就和右边gt指向的元素进行交换并且gt+1;如果nums[i]=基准,则i++跳过当前元素,进行下一次处理;

    public static void sort(int[] nums,int l,int r){
    		if (r<=l)return;
    		int lt=l,i=l+1,gt=r;
    		int pivot=nums[l];
    		while(i<=gt){
    			int cmp=compare(nums[i],pivot);
    			if(cmp<0) exch(nums,lt++,i++);
    			else if(cmp>0) exch(nums,i,gt--);
    			else i++;
    		}
    		sort(nums,l,lt-1);
    		sort(nums,gt+1,r);
    	}
    	private static void exch(int[] nums,int i,int j){
    		int temp=nums[i];
    		nums[i]=nums[j];
    		nums[j]=temp;
    	}
    	private static int compare(int a,int b){
    		if(a<b)return -1;
    		else if(a>b) return 1;
    		else return 0;
    	}
    
    * 对于包含大量重复元素的数组,它将排序时间从线性对数级降低到了线性级别!!!当存在重复元素时,三向切分无疑是最优的算法!
  • 相关阅读:
    iOS
    iOS
    iOS
    OpenGLES入门笔记四
    OpenGLES入门笔记三
    AVPlayer无法播放
    阿里云TTS重播报pointer being freed was not allocated错误
    [AVAssetWriter startWriting] Cannot call method when status is 1
    HTTP load failed (error code: -1009) / NSURLConnection finished with error
    在iPhone5上起始页卡着不动
  • 原文地址:https://www.cnblogs.com/taichiman/p/12953767.html
Copyright © 2020-2023  润新知