快排及荷兰国旗问题
問題一:將某一范圍[L,R]中的數按照給定值的target,分為左半部分為<=target的數,右半部分為>target的數
解決過程:定義兩個變量less和i,less用于指示當前<=區域的邊界位置,初始值為L-1,i用于遍歷該范圍的數。當arr[i] <= target時,將arr[i]和less下一個位置的元素交換,less++;否則,i++
整體上就是i用于遍歷待定區域, <=target的區域不斷向右擴張,壓縮待定區域,中間是>target的區域
//小于等于target的數放在閉區間【L, R】的左半部分,比target大的數放在閉區間【L, R】的右半部分//返回值是大于區域的第一個位置的下標public static int partition1(int[] arr, int target, int L, int R){int lessBorder = L - 1;while (L <= R){ //R是閉區間,也應該取到判斷if(arr[L] <= target){swap(arr, ++lessBorder, L++);}else{L++;}}return lessBorder + 1;}荷蘭國旗問題(partition):
問題描述:將給定范圍【L,R】區間的數按照 <target的區域在左邊,=target的區域在中間,>target的區域在右邊整理【L,R】區間的元素
解決過程:定義三個變量,less,i,more。less用于記錄<target的邊界,初始值為L-1;more用于記錄>target的邊界,初始值為R+1。i用于掃描待定區域。
while(i?< 右邊界){
? ? ? ? 如果arr[i] < target,交換arr[i] 和less所指的下一個元素,less++,i++
? ? ? ? 如果arr[i] > target,交換arr[i]和more所指的前一個元素,more--,i不變,因為交換后i位置的元素仍然是待定元素
? ? ? ? 如果arr[i] == target,不交換,直接i++
}
整體就是左右兩邊的區域向中間壓縮待定區域,剩下的中間是等于target的區域
//從大到小,大于區域,等于區域,小于區域public static int[] partition22(int[] arr, int target, int L, int R){int less = R + 1, more = L - 1;while(L < less){if(arr[L] > target){swap(arr,++more,L++);}else if(arr[L] < target){swap(arr, --less, L);}else{L++;}}return new int[]{more + 1, less - 1};}快速排序,給【L,R】范圍的數排序
(1)快排1.0,將該范圍的最后一個元素arr[R]作為target,對【L,R-1】范圍進行partition1,然后交換 >target區域的第一個元素和最后一個元素,確定最后一個元素在排好序后的位置,分別對剩余的左右兩邊區域進行上述操作遞歸,最終確定每個元素的位置
//快排1.0, 最差的時間復雜度為O(N^2)/*把待排數組的最后一個數作為目標值,使用partition1將除去最后一個數的元素進行左右區分,然后將大于區域的第一個值和最后一個值交換,找到最后一個值應該在的位置,同理,分別在左右兩邊的區域上重復該過程,直到整個數組都有序*/public static void quickSort1(int[] arr, int L, int R){if(arr == null || arr.length < 2) return;if(L < R){int index = partition1(arr, arr[R],L, R-1);swap(arr,index,R);quickSort1(arr,L,index - 1);quickSort1(arr,index + 1,R);//index位置的數已經確定,要從其后面開始分}}(2)快排2.0,同快排1.0將該范圍上的最后一個元素作為target,但是使用的是partition2,將【L,R】的數劃分為大于、等于、小于三個區域,確定等于target的一批數的位置,分別對小于區域和大于區域重復上述過程,進行遞歸操作,直到整個范圍有序
//快排2.0, 最差的時間復雜度為O(N^2)/*利用荷蘭國旗問題,以待排區間的最后一個位置數為target,將待排區間分為小于、等于、大于三個部分,確定一批等于target的位置,然后分別對小于區間和大于區間重復上述過程。*/public static void quickSort2(int[] arr, int L, int R){if(arr == null || arr.length < 2) return;if(L < R){int target = arr[R];int[] index = partition2(arr, target, L, R);quickSort2(arr, L, index[0] - 1);quickSort2(arr, index[1] + 1, R);}}由于1.0和2.0都是取范圍中的最后一個值作為target,當人為給出的數組是按照要求的順序時,時間復雜度為O(N^2)
(3)快排3.0,與快排3.0的唯一不同是,將target使用在該范圍下隨機選取一個位置的元素,將其與最后一個位置交換,之后就是2.0的過程了。隨機選取target,保證了無論是好的情況還是壞的情況概率相同,求累加長期期望,最后的時間復雜度是O(N*logN),額外空間:如果每次都選擇的中間位置則是最好情況O(logN),最壞的情況是O(N),每次都是選擇靠邊的位置
//快排3.0 ,時間復雜度O(N*logN)public static void quickSort3(int[] arr, int L, int R){if(arr == null || arr.length < 2) return;if(L < R){swap(arr, L+(int)(Math.random()*(R - L + 1)), R);//在[L,R]范圍內隨機選擇一個位置和R位置交換int target = arr[R]; // int[] index = partition2(arr,target,L,R);//從小到大排int[] index = partition22(arr,target,L,R);//從大到小排quickSort3(arr,L,index[0] - 1);quickSort3(arr,index[1] + 1,R);}}總結
- 上一篇: NAND和NOR Flash的区别
- 下一篇: 算法:荷兰国旗问题