package quickSortOptimized;
import java.util.Arrays;
public class QuickSortDemo {
public static void swap(int arr[], int a, int b) {//交换函数
int tmp = arr[a];
arr[a] = arr[b];
arr[b] = tmp;
}
public static void insertSort(int arr[], int start, int end) {//为快速排序优化准备插入排序;
for(int i=0;i<end;i++) {
for (int j=i+1;j>0;j--) {
if(arr[j]<arr[j-1]) {
swap(arr,j,j-1);
}
}
}
}
public static void print(int arr[]) {
System.out.println(Arrays.toString(arr));
}
public static void quickSort(int arr[],int start,int end) {//原始版快速排序
int low =start;
int high=end;
int key=arr[start];
while(low<high) {
while(arr[high]>key&&low<high) {//从high下标开始找到第一个比key小的下标,然后break;
high--;
}
while(arr[low]<key&&low<high) {//从low下标开始找到第一个比key大的下标,然后break;
low++;
}
if(low<high)swap(arr,low,high);
}
swap(arr,start,low);//因为是从高往低扫,所以,low=high的时候停留的下标数字一定比key小或等于key,这个时候和key交换.
//如果2个内层while和key比较的时候没有加等于号,则不需要这个交换.
System.out.println("low="+low+" high="+high+" start="+start+" end="+end+" key="+key);//打桩,方便调试
print(arr);
if(start<low)quickSort(arr, start, low-1);//从key的两头分别递归
if(high<end)quickSort(arr, high+1,end );
}
public static void optimizedQuickSort(int arr[],int start,int end) {//优化过的快速排序
int low;
insertSort(arr, start, start+2);
if(arr[start]==arr[start+1]) {
low=start;
}else {
low=start+1;
}//优化1.对前3个数字进行排序,然后取中位数作为key;用于避免每次都只能切1个数字来提高性能.
int high=end;
int key=arr[low];
int pointer=low+1;
while(pointer<high) {//优化2, 用pointer把整个数组扫一遍,小于key则和low++交换,大于key则和high--交换.如果等于则pointer++
if(arr[pointer]>key) {
swap(arr,low++,pointer++);
}else if(arr[pointer]>key) {
swap(arr,pointer,high--);
}else {
pointer++;
}//这样,start到low-1切成小于key的一块,low和pointer之间则是所有和key相等的值,high到end则是大于key的一块
//使所有等于key的一块不进入递归.
}
if(start+10<low) {//在数组切分至较小的时候切换到插入排序,因为在数组近似有序的情况下,插入排序远远快于快速排序
optimizedQuickSort(arr, start, low-1);
}else {
insertSort(arr, start, low-1);
}
if(pointer+10<end) {
optimizedQuickSort(arr, pointer, end);
}else {
insertSort(arr, pointer, end);
}
}
public static void main(String[] args) {
int arr[]=new int [45];
for(int i=0;i<arr.length;i++) {//生成随机数组
arr[i]=(int) (Math.random()*1000);
}
System.out.println("原始数组:");
print(arr);
//insertSort(arr, 0, arr.length-1);
//quickSort(arr, 0, arr.length-1);
optimizedQuickSort(arr, 0, arr.length-1);
System.out.println("排序后数组:");
print(arr);
}
}
写了下快速排序及其优化.前段时间本来我以为我弄懂了,结果今天重写的时候又出了好多问题....之前没有理解原版快速排序key归位的操作...只是看结果正确就没管了.....事实证明,学编程还是要多敲代码啊.....
快速排序思想是把待排序的数组切分成二分.首先选取一个key值,下标小的那份所有数都小于等于key,下标大的那部分所有数都大于等于key.
然后使用递归,继续切分,当分割到不能再分割的时候,整个数组就排序好了.....这种方法,每一次递归,都会使待排序的数字缩小..缩小,,缩小...具体为什么会比其他排序快,我数学不好....反正就他最快,
然而快速排序还有待优化空间.
第一种优化,避免了极端情况下只切割一个数字出来,使效率降低...而取3个数的中位数则是经过证明的最好的取key方法....
第二种优化,三项切分发,中间项把所有等于key的值聚集起来并且不再进入循环...在数组中有重复数字的情况下效率非常高.
第三种优化,则是在数组比较小的情况下切换到插入排序,因为数组较小的情况下再使用快速排序递归也要递归很多次....而且根据快速排序的特性,在数据切分至较小的情况下数组已经是近似有序了,而面对近似有序的数组,插入排序的速度最快.