思路:找一个中间数(主元),比主元数字小的放到主元前面,比大的放到主元后面。
伪代码
/**
*
* @param arr 待排序数组
* @param p 起点
* @param r 终点
* @param q 返回的最大值的下标
*/
quickSort(int[] A, int p, int r){
//找主元
q = partition(int[] A, int p, int r);
//主元前面的进行排序
quickSort(int[] A, int p, int q-1);
//主元后面的排序
quickSort(int[] A, int q+1, int r);
}
单项扫描寻找主元的关键思想
如下图:需要三个指针,pivot(主元)、sp(左指针)、bigger(右指针)。
- 若 sp <= pivot sp++;
- 若 sp > pivot swap(sp,bigger); bigger–;
单项扫描伪代码
* quickSort(A, p, r){
* if(p<r){
* int q = partition(A, p, r);
* //递归
* quickSort(A, p, q-1);
* quickSort(A, p+1, q);
* }
* }
*
* patition(A, p, r){
* int povit = p; 初始位置定为主元
* int sp = povit +1; 左指针
* int bigger = r; 最后一个元素为右指针
* while(sp<=bigger){
* if(A[sp]<=A[povit]){ 左指针比主元小,则左指针右移
* sp++;
* } else { 否则,交换左指针与右指针的数字,右指针左移
* swap(A, sp, bigger);
* bigger--;
* }
* }
当左指针大于右指针时,循环结束。
这里有一个小技巧:右指针永远指向了比主元大的前一个元素,
左指针永远指向了比主元大的第一个元素。(画图思考)
交换主元与bigger的值。返回 bigger 就是中间值下标
* swap(A, povit, bigger);
* return bigger;
* }
*
* @author lenovo
单项扫描的代码如下
/**
*
* @param arr 待排序数组
* @param p 起点
* @param r 终点
* @param q 返回的最大值的下标
*/
static void quickSort (int[] arr, int p, int r) {
if(p <= r){
int q = partition(arr, p, r);
quickSort(arr, p, q-1);
quickSort(arr, q+1, r);
}
}
/**
*
* @param arr
* @param pivot :主元
* @param sp:从前往后移动的指针
* @param bigger:从后往前的指针
* @return
*/
static int partition(int[] arr, int p, int r) {
int pivot = arr[p];
int sp = p + 1;
int bigger = r;
while(sp <= bigger){
if(arr[sp] <= pivot) {
sp++;
} else {
int temp = arr[sp]; arr[sp] = arr[bigger]; arr[bigger] =temp;
bigger--;
}
}
int temp = arr[p];
arr[p] = arr[bigger];
arr[bigger] = temp;
return bigger;
}
public static void main(String[] args) {
int [] arr = {3,2,1,4,5,3,9,7,8,12,90};
quickSort(arr, 0, arr.length-1);
for(int i = 0; i< arr.length ;i++){
System.out.print(arr[i]+" ");
}
}
双向扫描
找主元de思路:
定第一个元素为主元。
第二个元素和最后一个元素分别是左指针和右指针。
- 左<主元 左指针++;
- 左>主元 再判断右指针
- 右>主元 右指针++;
- 右<主元 左指针和右指针的值交换
- 再循环判断左指针,依次进行。
伪代码:
partition(A,p,r){
pivot = A[p]; //主元
left = p +1;
right = r;
while (left != right -1) {
while(A[left] <= pivot){ //左指针小于等于主元
left++;
}
while(A[right] > pivot){
right--;
}
swap(left,right);
left++;
right--;
}
}
双向扫描代码
易错点:一定还得加一个判断条件,left<=right。
如果待排序数组是 {3,2,1},而不加这个条件时就会出现left一直++;
static void quickSort(int[] A, int p, int r){
if(p < r){
int q = partition(A, p, r);
quickSort(A, p, q-1);
quickSort(A, q+1, r);
}
}
static int partition(int[] A, int p, int r) {
int pivot = A[p]; //主元
int left = p +1;
int right = r;
while (left <= right) {
/**
* 易错:
* 一定还得加一个判断条件,left<=right。
* 如果待排序数组是 {3,2,1},而不加这个条件时就会出现left一直++;
*/
while(left <= right && A[left] <= pivot){//左指针小于等于主元
left++;
}
while(left <= right && A[right] > pivot){
right--;
}
if(left < right) {
int temp = A[left];
A[left] = A[right];
A[right] = temp;
}
}
int temp = A[p];
A[p] = A[right];
A[right] = temp;
return right;
}
public static void main(String[] args) {
int[] arr ={1,5,7,5,3,8,0,445,3,2,1};
quickSort(arr, 0, arr.length-1);
for(int i =0 ; i < arr.length; i++){
System.out.print(arr[i]+" ");
}
}