基本思想:
快速排序时基于分治模式处理的,
对一个典型子数组A[p...r]排序的分治过程为三个步骤:
1.分解:
A[p..r]被划分为俩个(可能空)的子数组A[p ..q-1]和A[q+1 ..r],使得
A[p ..q-1] <= A[q] <= A[q+1 ..r]
2.解决:通过递归调用快速排序,对子数组A[p ..q-1]和A[q+1 ..r]排序。
3.合并。
伪代码:
QUICKSORT(A, p, r)
1 if p < r
2 then q ← PARTITION(A, p, r) //关键
3 QUICKSORT(A, p, q - 1)
4 QUICKSORT(A, q + 1, r)
核心部分:数组划分
快速排序算法的关键是PARTITION过程,它对A[p..r]进行就地重排:
PARTITION(A, p, r)
1 x ← A[r]
2 i ← p - 1
3 for j ← p to r - 1
4 do if A[j] ≤ x
5 theni ← i + 1
6 exchange A[i] <-> A[j]
7 exchange A[i + 1] <-> A[r]
8 return i + 1
时间复杂度分析:
最坏情况发生在划分过程产生的俩个区域分别包含n-1个元素和一个0元素的时候,
即假设算法每一次递归调用过程中都出现了,这种划分不对称。那么划分的代价为O(n),
因为对一个大小为0的数组递归调用后,返回T(0)=O(1)。
估算法的运行时间可以递归的表示为:
T(n)=T(n-1)+T(0)+O(n)=T(n-1)+O(n).
可以证明为T(n)=O(n^2)。
因此,如果在算法的每一层递归上,划分都是最大程度不对称的,那么算法的运行时间就是O(n^2)。
亦即,快速排序算法的最坏情况并不比插入排序的更好。
此外,当数组完全排好序之后,快速排序的运行时间为O(n^2)。
而在同样情况下,插入排序的运行时间为O(n)。
//注,请注意理解这句话。我们说一个排序的时间复杂度,是仅仅针对一个元素的。
//意思是,把一个元素进行插入排序,即把它插入到有序的序列里,花的时间为n。
再来证明,最快情况下,即PARTITION可能做的最平衡的划分中,得到的每个子问题都不能大于n/2.
因为其中一个子问题的大小为|_n/2_|。另一个子问题的大小为|-n/2-|-1.
在这种情况下,快速排序的速度要快得多。为,
T(n)<=2T(n/2)+O(n).可以证得,T(n)=O(nlgn)。
快排算法图示:
以上文字引用CSDN用户v_July_v: http://blog.csdn.net/v_JULY_v/article/details/6116297
快速排序算法的核心是Partition函数。
Partition函数可以有双向和单向两类只分,如下代码JavaCode中PartitionRight为单向函数,PartitionLeft和PartitionHoare为双向函数。
在PartitionLeft和PartitionRight函数中分别选取最左(First)和最右(Last)数组元素作为主元,而PartitionHoare函数中则可以选择任意位置的的元素作为主元。
Java Code:
public class QuickSort {
public static float[] QuickSortAlgorithm(float flt[], int start, int end ){
if (start<end) {
//int pos=Partition(flt, start, end);
int pos=PartitionLeft(flt, start, end);
QuickSortAlgorithm(flt, start, pos-1);
QuickSortAlgorithm(flt, pos+1, end);
}
return flt;
}
private static int PartitionRight(float flt[], int start, int end){
float primaryElement=flt[end];
int partitionPos=start-1;
for(int j=start;j<end;j++){
if (flt[j]<primaryElement) {
Swap(flt, partitionPos+1, j);
partitionPos++;
}
}
Swap(flt, partitionPos+1, end);
return partitionPos+1;
}
private static int PartitionLeft(float flt[], int start, int end){
float primaryElement=flt[start];
int i=start+1;
int j=end;
while(true){
while (flt[j]>primaryElement){j--;};
while (flt[i]<primaryElement){i++;};
if (i<j) {
Swap(flt, i, j);
}
else {
Swap(flt, start, j);
return j;
}
}
}
private static int PartitionHoare(float flt[], int start, int end){
float primaryElement=flt[start];// it can be any element in the array besides the first and last one.
int i=start;
int j=end;
while(i<j){
while (flt[j]>primaryElement){j--;}
while (flt[i]<primaryElement){i++;};
if (i<j) {
Swap(flt, i, j);
}
else {
return j;
}
}
return j;
}
private static void Swap(float flt[], int left, int right){
float temp=flt[left];
flt[left]=flt[right];
flt[right]=temp;
}
}