l 枢纽元(pivot):集合中的任意一个元素
如何取枢纽元:
1. 错误的做法是:将第一个元素作为枢纽元。如果输入是随即的,这样的做法还是可以接受的,可是如果输入是预排序的,这样就产生了一个劣质的分割,有可能所有的元素都被划入了S1,而S2没有元素。
2. 一种安全的做法:随即选取。这种方法非常安全,但是产生随即数开销很大。
3. 中值分割法:例:8,1,4,9,6,3,5,2,7,0。取第一个元素8,最后一个元素0,和[left+right]/2个元素6.于是枢纽元就是6.
l 分割策略:
分割是一种很容易出错或者低效的操作,安全的做法:第一部通过将枢纽元与集合最后一个元素交换,使枢纽元离开要分割的集合,i从集合的第一个元素开始,j从元素的倒数第二个开始。
8 1 4 9 0 3 5 2 7 6
↑ ↑
i j
假设所有的元素互异,在分割阶段要做的是:把所有的小元素移到数组的左边,大元素移到数组的右边,大小是相对于枢纽元的。
取得枢纽元的代码:(此处取法非常繁琐,可以利用一个小排序,如果要处理的是个元素数量比较小的数组,那么此处显然占据了很多效率,个人认为这也是快速排序不适用小数组的一个原因)
public int getIndexOfPivot(int[] list, int begin, int end) {
// 求的是中值的index
int middle = (begin+end)/2;
if((list[middle]>list[begin]&&list[middle]<=list[end])||(list[middle]<=list[begin]&&list[middle]>list[end])){
return (begin+end) /2;
}else if((list[end]>list[begin]&&list[end]<=list[middle])|| (list[end]>list[middle]&&list[end]<=list[begin])){
return end;
}else{
return begin;
}
}
移动过程:当i在j的左边时,讲i右移,当i指向的元素小于枢纽元时,并讲j左移,移过那些比枢纽元大的元素。当i和j停止时,i指向了一个大元素,j指向了一个小元素,如果i在j的左边,那么讲这两个元素互换。当i和j交错时,不在交换,这时将枢纽元与i所在位置的元素交换。最后利用分治法的思想,将枢纽元两侧的子数组进行递归排序,直到数组起始位置大于终止位置时,递归结束。
快速排序过程的完整代码实现如下:
public classQuickSort {
// core sort
public int[] sort(int[] list, int start, int end) {
if (start < end) {
int pivotPos = getIndexOfPivot(list,start, end);
int pivot = list[pivotPos];
// swap the pivot and the last element
list= swap(list, pivotPos, end);
int j = end;
// begin scan
if (j < 0) {
System.out.println("There is not enough element to sort!");
}
int i = start-1;
while (true) {
// find the first position
while (list[++i] < pivot ){
//移过那些小于枢纽元的元素
}
while((j-1)>=0&&list[--j] > pivot ) {
//移过那些大于枢纽元的元素
}
if (i < j) {
swap(list,i, j);
}else{
break;
}
}
// when the loop is over,then swap the element[i] and thepivot
swap(list,i, end);
sort(list,start, i-1);
sort(list,i + 1, end);
return list;
}else{
return list;
}
}
public int getIndexOfPivot(int[] list, int begin, int end) {
// 求的是中值的index
int middle = (begin+end)/2;
if((list[middle]>list[begin]&&list[middle]<=list[end])||(list[middle]<=list[begin]&&list[middle]>list[end])){
return (begin+end) /2;
}else if((list[end]>list[begin]&&list[end]<=list[middle])|| (list[end]>list[middle]&&list[end]<=list[begin])){
return end;
}else{
return begin;
}
}
public int[] swap(int[] a, int pos1, int pos2) {
int temp = a[pos1];
a[pos1]= a[pos2];
a[pos2]= temp;
return a;
}
public void print(int[] list) {
for (int i = 0; i < list.length; i++) {
System.out.println(list[i]);
}
}
public static void main(String[] args) {
int[] a = { 8, 1, 4, 9, 6, 3, 5, 2, 7, 0 };
QuickSortqs = newQuickSort();
a= qs.sort(a, 0, 9);
qs.print(a);
}
}
l 快速排序的分析:
最差情况:枢纽元始终是最小元素,时间复杂度为O(N2);
最好情况:枢纽元始终在中间,时间复杂度为O(NLogN);
平均情况:O(NLogN).