【排序】快速排序(Quick Sort)

快速排序(Quick Sort)
原理:通过一趟排序将待排序的数组分割成独立的两部分,其中一部分均比另部分小,然后分别对着两部分递归排序即可,最终达到排序目的

就是找到一个枢轴,然后枢轴左边的数字均小于该枢轴,右边的均大于该枢轴,然后对左右部分递归调用即可。本质上是冒泡法的升级,属于交换排序,只不过增大了移动和比较的距离,将大的数字从后面直接移动到后面,小的数字直接移动到前面。

时间复杂度: O ( n log ⁡ n ) O(n\log n) O(nlogn)
import java.util.Arrays;
public class test {
	public static void QuickSort(int[] arr, int low, int high) {
		int pivot;
		if (low < high) {
			//将数组arr[low.....high]一分为2,返回枢轴位置
			//这个时候枢轴左边的数均小于枢轴,右边的数均大于枢轴
			pivot = Partition(arr, low, high);
			//分别对枢轴左右部分递归
			QuickSort(arr, low, pivot-1);
			QuickSort(arr, pivot+1, high);
		}
	}
	
	//交换数组中数字,使得枢轴记录到位,并返回其所在位置(索引)
	//此时在它之前的数字均小于等于该枢轴,后面的数字均大于等于该枢轴
	public static int Partition(int[] arr, int low, int high) {
		//初始化数组的第一个数字为枢轴
		int pivotkey = arr[low];	
		//从数组两端交替向中间扫描
		while(low < high) {	
			//如果右边的数字大于枢轴,那么继续向后扫描,直到找到右边比枢轴小的数字
			while(low < high && arr[high] >= pivotkey) high--;
			//将比枢轴还小的数字交换到左边
			swap(arr, low, high);
			
			while(low < high && arr[low] <= pivotkey) low++;
			swap(arr, low, high);
		}
		return low;//返回枢轴位置(索引)
	}
	
	public static void swap(int[] arr, int low, int high) {
		int temp;
		temp = arr[low];
		arr[low] = arr[high];
		arr[high] = temp;
	}
	    
	public static void main(String[] args) {
		int [] nums = {9, 1, 5, 8, 3, 7, 4, 6, 2};
		QuickSort(nums, 0, nums.length-1);
		System.out.println(Arrays.toString(nums));
	}
}
优化1:选取枢轴

思想:因为一般取第一个数字作为第一个枢轴,最好的情况是枢轴是中间数字。。
三数取中:取左端、右端和中间数先进行排序,然后取中间的数作为枢轴

public static int Partition(int[] arr, int low, int high) {
		
		//################################ 优化1 ###############################
		int m = low + (high - low)/2;
		if(arr[low] > arr[high]) swap(arr, low, high);	//保证左端较小
		if(arr[m] > arr[high]) swap(arr, high, m);		//保证中间较小
		if(arr[m] > arr[low]) swap(arr, m, low);			//保证左端较小
		
		//初始化数组的第一个数字为枢轴
		int pivotkey = arr[low];	
		//从数组两端交替向中间扫描
		while(low < high) {	
			//如果右边的数字大于枢轴,那么继续向后扫描,直到找到右边比枢轴小的数字
			while(low < high && arr[high] >= pivotkey) high--;
			//将比枢轴还小的数字交换到左边
			swap(arr, low, high);
			
			while(low < high && arr[low] <= pivotkey) low++;
			swap(arr, low, high);
		}
		return low;//返回枢轴位置(索引)
	}
优化2:不必要的替换

思想枢轴这个关键字其实没必要一直交换,可以采用替换而不是交换

public static int Partition(int[] arr, int low, int high) {
		
		//################################ 优化1 ###############################
		int m = low + (high - low)/2;
		if(arr[low] > arr[high]) swap(arr, low, high);	//保证左端较小
		if(arr[m] > arr[high]) swap(arr, high, m);		//保证中间较小
		if(arr[m] > arr[low]) swap(arr, m, low);			//保证左端较小
		
		//初始化数组的第一个数字为枢轴
		int pivotkey = arr[low];
		
		//备份枢轴关键字
		int temp = pivotkey;				//change 1
		
		//从数组两端交替向中间扫描
		while(low < high) {	
			//如果右边的数字大于枢轴,那么继续向后扫描,直到找到右边比枢轴小的数字
			while(low < high && arr[high] >= pivotkey) high--;
			//采用替换而不是交换
			arr[low] = arr[high];			//change 2
			
			while(low < high && arr[low] <= pivotkey) low++;
			//采用替换而不是交换
			arr[high] = arr[low];			//change 3
		}
		//将枢轴数字返回左端
		arr[low] = temp;					//change 4
		return low;//返回枢轴位置(索引)
	}
优化3:小数组

思想:快速排序算法适用于大的数组,如果数组特别小,建议适用直接插入排序,所以可以提前判断一下数组长度,一般选7

优化4:尾递归

思想:将尾部的两次递归减少成一次
因为第一次递归后,变量low就没用了,所以直接将pivot+1赋值给low;再循环后,来一次Partition(arr, low, high),效果等同于QuickSort(arr, pivot+1, high)

public static void QuickSort(int[] arr, int low, int high) {
		int pivot;
		while (low < high) {			//change1 while替换if
			//将数组arr[low.....high]一分为2,返回枢轴位置
			//这个时候枢轴左边的数均小于枢轴,右边的数均大于枢轴
			pivot = Partition(arr, low, high);
			//分别对枢轴左右部分递归
			QuickSort(arr, low, pivot-1);
			low = pivot + 1;			//change2 尾递归
		}
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值