快速排序

一、快速排序算法:划分是问题的关键。


    1.分解:将数组划分为两个数组,使得一个数居中,左侧都小于等于他,右侧都大于等于他。其中计算中间数下标也是划分过程的一部分。
    2.解决:通过递归调用快速排序,对于子数组(左右数组)进行排序。
    3.合并:因为子数组都是原址排序的,所以整体数组已经有序。
    伪代码:
    QuickSort(A,p,r)
    if(p<r)
    q=partition(A,p,r)//得到中间元素的下标
    QuickSort(A,p,q-1)
    QuickSort(A,q+1,r)

二、快排之单向扫描分区法


    -一遍扫描法的思想是,用两个指针将数组划分为三个区间。
    -扫描指针sp-(scan_pos):左边是确认小于等于主元的。
    -未知区间末指针bp-(next_bigger_pos):末指针的右边区间为确认大于主元的元素。扫描指针到某个指针(next_bigger_pos)中间为未知的。
    <=sp 右移
    > 交换并bp左移
    边界:如果最后一个扫描元素大于主元,bp左移之后小于了sp
         如果最后一个扫描的元素小于主元,sp的右移导致,sp大于bp
        伪代码:
       //单项扫描分区法
        partition(A,p,r):
        pivot=A[p];//主元
        sp=p+1;//扫描指针
        bp=r;//右侧指针
        while(sp<bp){
        if(sp<=pivot)//扫描指针小于主元,扫描指针右移
        sp++;
        else
        swap(A,sp,bp);//扫描指针大于主元,两指针的元素交换,右侧指针左移
        bp--;
        }
        swap(A,p,bp);
        return bp; 

import java.util.Arrays;
public class 快排之单向扫描分区法 {
		  	 public static void main(String[] args) {
			  int arr[]=getRandomArr(10,1,20);
			  System.out.println("原数组:"+Arrays.toString(arr));
			  quickSort(arr,0,arr.length-1);
			  System.out.println("排序后:"+Arrays.toString(arr));
	}

		public static void quickSort(int[]A,int p,int r) {
			  if(p<r) {
				  int q=partition(A,p,r);
				  quickSort(A,p,q-1);
				  quickSort(A,q+1,r);
			  }
		  }
		//单项扫描分区法
		  public static int partition(int[] A, int p, int r) {
			int pivot=A[p];//主元
			int sp=p+1;//扫描指针
			int bp=r;//右侧指针
			while(sp<=bp) {
				if(A[sp]<=pivot)//扫描元素小于等于主元,扫描指针右移
					sp++;
				else {
					swap(A,sp,bp);//扫描元素大于主元,两指针元素交换,右指针左移
					bp--;	
				}
			}
			swap(A,p,bp);
			return bp;
		}
		  //获取随机数组
		  public static int[] getRandomArr(int length, int min, int max) {
				int arr[]=new int[length];
				for(int i=0;i<length;i++) {
					/*Math.random()能够产生[0,1)的浮点数。
					 * 返回给定范围的随机整数
					 * Math.random()*(最大数-最小数+1)+最小数*/
					arr[i]=(int)(Math.random()*(max-min+1)+min);
				}
				return arr; 
				}
		 // 在数组内原址交换元素
		  public static void swap(int[] arr, int i, int j) {
			    int tmp = arr[i];
			    arr[i] = arr[j];
			    arr[j] = tmp;
			  }
		
		  }


三、 快排之双向扫描分区法 


        双向扫描的思路是,头尾指针往中间扫描,从左找到大于主元的元素,从右找到小于等于主元的元素
        二者交换,继续扫描,直到左侧无大元素,右侧无小元素。左先右后。
        伪代码:
        //双向扫描法
        partition2(A,p,r){
        pivate=A[p];//主元定为第一元素
        left=p+1;//第二个元素
        right=r;//最后一个元素
        while(left<=right){
        //left不停往右走,直到遇到大于主元的元素
        //循环退出时,left一定是指向第一个大于主元的位置
        while(left<=right&&A[left]<=pivot)   left++;
        //循环退出时,right一定是指向最后一个小于等于主元的位置
        while(left<=right&&A[left]>pivot)   right--;
        //left指针与right指针交换
        if(left<right)//等于交换没有意义
        swap(A,left,right);
        }
        //while退出时,两者交错,且right指向的是最后一个小于等于主元的位置,也就是主元应该是待的位置。
        swap(A,p,right);
        return right;
        }

import java.util.Arrays;
public class 快排之双向扫描分区法 {
	public static void main(String[] args) {
		  int arr[]=getRandomArr(10,1,20);
		  System.out.println(Arrays.toString(arr));
		  quickSort2(arr,0,arr.length-1);//双向扫描分区法
		  System.out.println(Arrays.toString(arr));
} 
	//双向扫描分区法
	  public static void quickSort2(int[]A,int p,int r) {
		  if(p<r) {
			  int q=partition2(A,p,r);
			  quickSort2(A,p,q-1);
			  quickSort2(A,q+1,r);
		  }
	  }
			public static int partition2(int[] A, int p, int r) {
				//三点中值法优化主元
				int midIndex=(r+p)/2;
				int midIndexValue=-1;
				if(A[p]<=midIndexValue&&A[p]>A[r]){
				midIndexValue=p;
				}else if(A[r]<=midIndexValue&&A[r]>A[p]){
				midIndexValue=r;
				}else{  
				midIndexValue=midIndex;
				}
			    swap(A,p,midIndexValue);
			    
			int pivate=A[p];//主元一般定为首元素
			int left=p+1;//第二个元素
			int right=r;//最后一个元素
			while(left<=right){
			//left不停往右走,直到遇到大于主元的元素
			//循环退出时,left一定是指向第一个大于主元的位置
			while(left<=right&&A[left]<=pivate)   left++;
			//循环退出时,right一定是指向最后一个小于等于主元的位置
			while(left<=right&&A[right]>pivate)   right--;
			if(left<right) 
			swap(A,left,right);
			}
			//while退出时,两者交错,且right指向的是最后一个小于等于主元的位置,
			//也就是主元应该是待的位置。
			swap(A,p,right);
			return right;
			}
	    
	 //获取指定范围指定个数的随机数组成的数组
	  public static int[] getRandomArr(int length, int min, int max) {
		    int[] arr = new int[length];
		    for (int i = 0; i < length; i++) {
		      arr[i] = (int) (Math.random() * (max + 1 - min) + min);
		    }
		    return arr;
		  }
	 // 在数组内原址交换元素
	  public static void swap(int[] arr, int i, int j) {
		    int tmp = arr[i];
		    arr[i] = arr[j];
		    arr[j] = tmp;
		  }
}

三、 快排在工程实践中的优化

1.三点中值法优化主元----在p,r,mid之间,选一个中间值作为主元。

2.绝对中值法

3.待排序列表较短时,用插入排序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值