经典排序——快排及三种优化
快排时间复杂度为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——小数组时,直接使用插入排序更快
代码,后面再加