单项扫描

思路:找一个中间数(主元),比主元数字小的放到主元前面,比大的放到主元后面。

伪代码

/**
	 * 
	 * @param arr 待排序数组
	 * @param p   起点
	 * @param r	    终点
	 * @param q	   返回的最大值的下标
	 */
quickSort(int[] A, int p, int r){
	//找主元
	q = partition(int[] A, int p, int r);
	//主元前面的进行排序
	quickSort(int[] A, int p, int q-1);
	//主元后面的排序
	quickSort(int[] A, int q+1, int r);
}

单项扫描寻找主元的关键思想
如下图:需要三个指针,pivot(主元)、sp(左指针)、bigger(右指针)。

  1. 若 sp <= pivot sp++;
  2. 若 sp > pivot swap(sp,bigger); bigger–;

【排序】快速排序---单项扫描和双向扫描_待排序

单项扫描伪代码


 * quickSort(A, p, r){
 *  	if(p<r){
 *  		int q = partition(A, p, r);
 *  		//递归
 *  		quickSort(A, p, q-1);
 *  		quickSort(A, p+1, q);
 *  	}
 * }
 * 
 * patition(A, p, r){
 *		int povit = p;     初始位置定为主元
 *		int sp = povit +1;      左指针
 *		int bigger = r;         最后一个元素为右指针
 *		while(sp<=bigger){      
 *			if(A[sp]<=A[povit]){     左指针比主元小,则左指针右移
 *				sp++;
 *			} else {               否则,交换左指针与右指针的数字,右指针左移
 *				swap(A, sp, bigger);
 *				bigger--;
 *			}  
 *		}
		当左指针大于右指针时,循环结束。
	
		这里有一个小技巧:右指针永远指向了比主元大的前一个元素,
						  左指针永远指向了比主元大的第一个元素。(画图思考)
						  
		交换主元与bigger的值。返回 bigger 就是中间值下标  
 *		swap(A, povit, bigger);  
 *		return bigger;
 * }
 * 
 * @author lenovo

单项扫描的代码如下

/**
	 * 
	 * @param arr 待排序数组
	 * @param p   起点
	 * @param r	    终点
	 * @param q	   返回的最大值的下标
	 */
	static void quickSort (int[] arr, int p, int r) {
		if(p <= r){
			int q = partition(arr, p, r);
			quickSort(arr, p, q-1);
			quickSort(arr, q+1, r);
		}
	}
	
	/**
	 * 
	 * @param arr
	 * @param pivot :主元
	 * @param sp:从前往后移动的指针
	 * @param bigger:从后往前的指针
	 * @return
	 */
	static int partition(int[] arr, int p, int r) {
		int pivot = arr[p];
		int sp = p + 1;
		int bigger = r;
		
		while(sp <= bigger){
			if(arr[sp] <= pivot) {
				sp++;
			} else {
				int temp = arr[sp]; arr[sp] = arr[bigger]; arr[bigger] =temp;
				bigger--;
			}
		}
		
		int temp = arr[p];
		arr[p] = arr[bigger];
		arr[bigger] = temp;
		return bigger;
	}

	public static void main(String[] args) {
		int [] arr = {3,2,1,4,5,3,9,7,8,12,90};
		quickSort(arr, 0, arr.length-1);
		for(int i = 0; i< arr.length ;i++){
			System.out.print(arr[i]+" ");
		}
	}
双向扫描

找主元de思路
定第一个元素为主元。
第二个元素和最后一个元素分别是左指针和右指针。

  1. 左<主元 左指针++;
  2. 左>主元 再判断右指针
  3. 右>主元 右指针++;
  4. 右<主元 左指针和右指针的值交换
  5. 再循环判断左指针,依次进行。

伪代码:
partition(A,p,r){
pivot = A[p]; //主元
left = p +1;
right = r;

while (left != right -1) {
	while(A[left] <= pivot){  //左指针小于等于主元
		left++;
	}
	while(A[right] > pivot){ 
		right--;
	}
	swap(left,right);  
	left++;
	right--;
}

}

双向扫描代码

易错点:一定还得加一个判断条件,left<=right。
如果待排序数组是 {3,2,1},而不加这个条件时就会出现left一直++;

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);
		}
	}
	
	static int partition(int[] A, int p, int r) {
		int pivot = A[p]; //主元
	  	int left = p +1;
	  	int right = r;
	  	
	  	while (left <= right) {
	  		/**
	  		 * 易错:
	  		 * 一定还得加一个判断条件,left<=right。
	  		 * 如果待排序数组是 {3,2,1},而不加这个条件时就会出现left一直++;
	  		 */
	  		while(left <= right && A[left] <= pivot){//左指针小于等于主元
	  			left++;
	  		}
	  		while(left <= right && A[right] > pivot){
	  			right--;
	  		}
	  		
	  		if(left < right) {
	  			int temp = A[left];
		  		A[left] = A[right];
		  		A[right] = temp;
	  		}
	  	}
	  	
	  	int temp = A[p];
  		A[p] = A[right];
  		A[right] = temp;
	  	
  		return right;
	}
	
	public static void main(String[] args) {
		int[] arr ={1,5,7,5,3,8,0,445,3,2,1};
		quickSort(arr, 0, arr.length-1);
		
		for(int i =0 ; i < arr.length; i++){
			System.out.print(arr[i]+" ");
		}
		
	}