快排之三指针扫描分区
适用于选取主元时,所选主元在数组中有多个相同值。若数组中没有主元的相同值,没有必要用三指针扫描分区法。
下面主要分析的是partition部分的方法:
三个指针:less(指向第一个等于主元的位置);sc(向右移动的扫描指针,指针左侧皆小于等于主元);bigger(指针右侧皆大于主元)
在分区时有三个阶段:
- 阶段1:
sp指针一直向右移,当扫描到小于主元的值时sc++,当扫描到大于主元的值时,其做法同单向扫描分区法一直(即swap(arr,sp,bigger)并且bigger- -),当扫描到等于主元的值时,将less指针放置于sc指针的位置上,此时less指针指向了第一个等于主元的位置。 随后进入阶段2。 - 阶段2:
sp指针依旧向右移动,当扫描到小于主元的值时,swap(arr,sp,e)并且e++,这样做是为了确保小于主元的值始终在e指针的左侧。当扫描到等于主元的值时,sp++。当扫描到大于主元的值时swap(arr,sp,bigger)并且bigger- -。 - 阶段3
经过上述两个阶段后,数组被划分成下图。
主元依旧在begin位,此时e指向第一个等于主元位,bigger指向最后一个等于主元位。
我们所要做的就是将swap(arr,begin,e - 1)而后e- -,如此e左侧的全小于主元,[e,bigger]都等于主元,bigger右侧全大于主元,分区完成。用数组保存e和bigger的位置,并将数组返回给quickSort方法中,最后在quickSort中递归调用quickSort[begin,e - 1]与[bigger + 1,end]排序即可。
public class 快排之三指针扫描分区 {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr = { 8, 8, 7, 6, 5, 0, 4, 8, 3, 2, 8, 7, 10 };
quickSort(arr, 0, arr.length - 1);
for (int num : arr) {
System.out.print(num + " ");
}
}
private static void quickSort(int[] arr, int begin, int end) {
if (begin >= end) {
return;
}
int[] position = partition(arr, begin, end);
quickSort(arr, begin, position[0] - 1);
quickSort(arr, position[1] + 1, end);
}
// 要考虑到数组中没有与主元相等的特殊情况
private static int[] partition(int[] arr, int begin, int end) {
int pivot = arr[begin];
int sp = begin + 1;
int e = begin + 1;// 相等指针
int bigger = end;
while (sp <= bigger) {
if (arr[sp] < pivot) {
sp++;
} else if (arr[sp] > pivot) {
swap(arr, sp, bigger);
bigger--;
} else {
e = sp;
sp++;
break;
}
}
while (sp <= bigger) {
if (arr[sp] < pivot) {// 小于主元时,交换位置,e++
swap(arr, sp, e);
e++;
sp++;
} else if (arr[sp] > pivot) {
swap(arr, sp, bigger);
bigger--;
} else {// 等于主元时,sp++
sp++;
}
}
// 假如不存在等于主元的元素
if (arr[e] != pivot) {
swap(arr, begin, bigger);
int[] position = { bigger, bigger };
return position;
}
// 若存在与主元相等的元素,主元依旧在begin位,此时e指向第一个等于主元位,bigger指向最后一个等于主元位
else {
swap(arr, begin, e - 1);
e--;
int[] position = { e, bigger };// 记录两个端点位置
return position;
}
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}