做了《劍指offer》中最小的k個數的題目(詳情可見這篇博客https://blog.csdn.net/weixin_42582008/article/details/100937950 )
和數組中出現次數超過一半的數字的題目(詳情可見這篇博客https://blog.csdn.net/weixin_42582008/article/details/100760644)
都可以用partition解決,雖然都不是最佳解法。但感覺自己對partition的過程不是很瞭解,就回顧了一下partition和快速排序。
1.partition
partition可以將數組分爲三部分,假如選定最後一個數字temp作爲基準,那麼從左向右分別爲小於temp的部分,等於temp的部分,大於temp的部分。一般情況下,爲了簡單起見,不需要將大於temp的數和等於temp的數分開處理(但還是數組還是劃分爲三部分,只不過第二部分只是一個數,其他和temp相等的數和大於temp的數一樣處理)partition函數如下所示,這對於處理“求第k小的元素這種問題是沒有問題的,這樣做快排也沒問題)
public int partition(int[] array,int start,int end){
int temp = array[end];
int less = start-1;
for(int i=start;i<end;i++){
if(array[i]<temp){
swap(array,++less,i);
}
}
swap(array,++less,end);
return less;
但是也可以嚴格分爲三部分,第二部分不是一個數,而是所有和temp相等的數(當然,如果只有一個,那麼也是一個數)。partition代碼如下所示,下標小於等於less的數爲小於temp的,下標大於等於more的數爲大於temp的,之間的數爲等於temp的.從start開始遍歷數組,如果遍歷到的元素和temp相等,什麼都不做,繼續遍歷下一個,如果小於temp,那麼和less之後的數交換,less=less+1,繼續遍歷下一個數,如果大於temp,那麼和more之前的數交換,more=more-1,這時start不能加1,因爲不知道交換過來的數和temp的大小關係。直到start=more,遍歷結束。將end上的數和more位置的數交換,more=more+1。返回的less和more滿足下標小於等於less的數爲小於temp的,下標大於等於more的數爲大於temp的,之間的數爲等於temp。partiton過程結束。
public static int[] partition(int[] arr, int start, int end) {
int less = start - 1;
int more = end;
int temp = arr[end];
while (start<more){
if (arr[start] < temp) {
swap(arr, ++less, start++);
} else if (arr[start] > temp) {
swap(arr, --more, start);
}else{
start++;
}
}
swap(arr,more++,end);
return new int[] {less,more};
}
2.快排與隨機快排
partition過程明瞭了,快排也就簡單了 ,只需要將數組進行一次partition,再將第一和第三部分再進行quickSort,注意退出遞歸的條件就可以了。之所以有隨機快排,是因爲,普通快排再數組有序時,時間複雜度爲O(n^2),而隨機快排可以不只是以end位置的數爲基準,可以在有序的情況下時間複雜度仍爲O(nlogn)。隨機快排和快排差別只在於有無這句代碼,即是否在partition前將end位置的數與[start,end]位置上隨機的一個的數交換一下。
swap(arr,(int)(start+Math.random()*(end-start+1)),end);
完整快排代碼:
import java.util.Arrays;
public class JustTry {
public static void main(String[] args) {
//隨便寫的一個測試用例
int[] input = {2,3,1,43,1,434,1,43,14,1,2,34,4,5,56,56};
quickSort(input,0,input.length-1);
System.out.println(Arrays.toString(input));
}
public static void quickSort(int[] arr){
if(arr == null || arr.length<2){
return;
}
quickSort(arr,0,arr.length-1);
}
public static void quickSort(int[] arr, int start, int end) {
if (arr == null || arr.length < 2 || start >= end) {
return;
}
//有下面這段代碼,爲隨機快排,否則爲普通快排,(int)(start+Math.random()*(end-start+1))產生一個[start,end]的隨機數
swap(arr,(int)(start+Math.random()*(end-start+1)),end);
int[] index = partition(arr, start, end);
quickSort(arr, start, index[0]);
quickSort(arr, index[1], end);
}
public static int[] partition(int[] arr, int start, int end) {
int less = start - 1;
int more = end;
int temp = arr[end];
while (start<more){
if (arr[start] < temp) {
swap(arr, ++less, start++);
} else if (arr[start] > temp) {
swap(arr, --more, start);
}else{
start++;
}
}
swap(arr,more++,end);
return new int[] {less,more};
}
public static void swap(int[] arr ,int i,int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}