快速排序(英语:Quicksort),又称划分交换排序(partition-exchange sort),通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
步骤为:
- 从数列中挑出一个元素,称为"基准"(pivot),
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
- 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
- 递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
java 的几种实现:
public class QuickSortTest {
public static void main(String[] args) {
StopWatch stopWatch = new StopWatch();
int[] input1 = {2,5,4,89,20,89,6,0,54,78,2};
stopWatch.start();
quickSortByMiddle(input1, 0, input1.length-1);
PrintUtils.print(input1);
stopWatch.stop();
stopWatch.start();
quickSortByMiddle(input1, 0, input1.length-1);
PrintUtils.print(input1);
stopWatch.stop();
int[] input2 = {2,5,4,89,20,89,6,0,54,78,2};
stopWatch.start();
quickSortByMiddle1(input2, 0, input2.length-1);
PrintUtils.print(input2);
stopWatch.stop();
int[] input3 = {2,5,4,89,20,89,6,0,54,78,2};
stopWatch.start();
quick_sort(input3, 0, input3.length-1);
PrintUtils.print(input3);
stopWatch.stop();
System.out.println(stopWatch);
}
/**
* 以中间位置为基准,关注指针,当 pivot 发生交换时,移动 pivot 指针
* @param arr
* @param left
* @param right
*/
public static void quickSortByMiddle(int[] arr, int left, int right){
if(left >= right){
return;
}
int pivotPointer = (right + left) / 2;
int l = left;
int r = right;
while (l < r){
//从左向右查找,找到一个大于 pivot 的值或 l == pivot 为止
while(l < pivotPointer && arr[l] < arr[pivotPointer]){
l++;
}
//从右向左查找,找到一个小于 pivot 的值或 r == pivot 为止
while (r > pivotPointer && arr[r] > arr[pivotPointer]){
r--;
}
//左侧找到的数,和右侧找到的数进行交换
int temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
//移动pivot
if (l == pivotPointer){
pivotPointer = r;
}else if (r == pivotPointer){
pivotPointer= l;
}
//移动左右指针,进入下一轮
if (l < pivotPointer){
l++;
}
if (r > pivotPointer){
r--;
}
}
/**
* 说明左右两个指针都已经移动到了pivot
* pivot左侧都小于pivot,右侧都大于pivot
* 所以无需交换
*/
if (r==l){
quickSortByMiddle(arr, left, pivotPointer - 1);
quickSortByMiddle(arr, pivotPointer + 1, right);
}
}
/**
* 以中间位置为基准,忽略指针,只关心 pivot 的值
* @param arr
* @param left
* @param right
*/
public static void quickSortByMiddle1(int[] arr, int left, int right){
int pivot = arr[(right + left) / 2];
int l = left;
int r = right;
while (l < r){
//从左向右查找,找到一个大于 pivot 的值或 l == pivot 为止
while(l < r && arr[l] < pivot){
l++;
}
//从右向左查找,找到一个小于 pivot 的值或 r == pivot 为止
while (l < r && arr[r] > pivot){
r--;
}
if (l >= r){
break;
}
//左侧找到的数,和右侧找到的数进行交换
int temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
if (arr[l]==pivot){
l++;
}
if (arr[r]==pivot){
r--;
}
}
if (left == r){
r--;
l++;
}
if (left < r){
quickSortByMiddle1(arr, left, r);
}
if (right > l){
quickSortByMiddle1(arr, l, right);
}
}
/**
* 以左侧第一个元素作为基准,这个写法还真是简洁啊~
* @param myList
* @param first
* @param last
*/
public static void quick_sort(int[] myList,int first,int last){
if(first>=last){
return;
}
int mid_value = myList[first];
int low = first;
int high = last;
while(low=mid_value){
high--;
}
myList[low] = myList[high];
while(low
时间复杂度
- 最优时间复杂度:O(nlogn)
- 最坏时间复杂度:O(n2)
- 稳定性:不稳定