Quick Sort
翻译部分
综述
快速排序是基于Partition(分区处理)的高效排序算法,或许也可以说是分而治之的思想。
他会把数组分割成两个小的数组,一个数组保有小于pivot(枢纽)的元素,一个数组保有大于pivot的元素。
快排会对分区调用自身再次处理,这就是递归。
这个算法是很有效率的,平均和最坏的复杂度都是O(nlogn)
,n就是有多少个元素。快排对于处理海量数据很好。
Partition
你可以观看DATA_Struct app 上的动画,来理解partition的原理。
Pivot 算法
步骤大致如下:
- 选择最高位(最后一位,其实第一位也行,必然行)的元素作为pivot(枢纽)
- 召唤两个变量来指向左和右
- 左边的指针指向低位的索引
- 右边的指针指向高位的索引
- 当左边指针指向的元素小于pivot元素,左边指针不断右移
- 当右边指针指向的元素大于pivot元素,右边指针不断左移
- 当左右指针遇到他们理想的元素(左遇大,右遇小)便交换他们
- 如果发现左边的指针位置>=右边指针的位置,他们就是相遇了,这个相遇的地方就是新的pivot
- pivot会作为partition函数的返回值返回,继续partition
快排中的找pivot的伪代码
function partitionFunc(left, right, pivot)
lefPointer = left - 1
rightPointer = right
while TRUE do
while A[++leftPointer] < pivot do
//actually do nothing
end while
while rightPointer > 0 && A[--rightPointer] > pivot do
//actually do nothing
end while
if leftPointer >= rightPointer
break
else
swap leftPointer, rightPointer
end if
end while
swap leftPointer, right
return leftPointer
end function
快排的伪代码
基于我们给出上述的pivot求解代码,使用之,我们会得到更小的分区,每个分区再使用quickSort,以递归的方式,最终就这样解决问题了。
我们可以如下来写quickSort的算法
- 让最右侧的索引作为pivot
- 对整个数组partition(会得到左右两个partition后的小数组)
- 对左侧数组快排
对右侧数组快排
- 快排的具体伪代码
procedure quickSort(left, right)
if right - left <= 0
return
else
pivot = A [right]
partition = partitionFunc(left, right, pivot)
quickSort(left, partition - 1)
quickSort(partition + 1, right)
end if
end procedure
Java实现
public class QuickSort {
public static void quickSort(int[] array){
if(array != null){
quickSort(array, 0, array.length-1);
}
}
private static void quickSort(int[] array,int beg,int end){
if(beg >= end || array == null)
return;
int p = partition(array, beg, end);
quickSort(array, beg, p-1);
quickSort(array, p+1, end);
}
}
上面就是快排主要的框架,最重要就是partition方法,它是划分并找到下次分割排序的位置p
常用的partition方法
//方法一:形象地来说是:
// 以first作为pivot,i去往后寻找一个大于first的元素
//j从end往前寻找一个小于first的元素
//i,j都发现了自己希望的元素,便停下来,交换。
private static int partition(int[] array, int beg, int end) {
int first = array[beg];
int i = beg, j = end;
while (i < j) {
while (array[i] <= first && i < end) {
i++;
}
while (array[j] > first && j >= beg) {
j--;
}
if (i < j) {
array[i] = array[i] ^ array[j];
array[j] = array[i] ^ array[j];
array[i] = array[i] ^ array[j];
}
}
if (j != beg) {
array[j] = array[beg] ^ array[j];
array[beg] = array[beg] ^ array[j];
array[j] = array[beg] ^ array[j];
}
return j;
}
第二种partition方法实现
//这个形象来说是:i作为一个拖后腿的小兵,而j是一个也是从beg开始的大将,j它会
//在前方寻找array[j] <= array[end]的元素(小的,老弱病残的元素),再让i接手
private static int partition(int[] array,int beg,int end){
int last = array[end];
int i = beg -1;
for (int j = beg; j <= end-1; j++) {
if(array[j] <= last){
i++;
if(i != j){
array[i] = array[i]^array[j];
array[j] = array[i]^array[j];
array[i] = array[i]^array[j];
}
}
}
if((i+1) != end){
array[i+1] = array[i+1]^array[end];
array[end] = array[i+1]^array[end];
array[i+1] = array[i+1]^array[end];
}
return i+1;
}