Java經(jīng)典快排思想以及快排的改進(jìn)講解
一.經(jīng)典快排思想
前提條件:給定一個(gè)無(wú)序數(shù)組arr
- 取這個(gè)數(shù)組最后一個(gè)數(shù) num 作為標(biāo)準(zhǔn),將前面部分的數(shù)分為兩部分,使得<=num的部分在左邊,>num的數(shù)在右邊;
- 然后將最后一個(gè)數(shù)和>num部分的第一個(gè)數(shù)進(jìn)行交換,就使得原本在數(shù)組最后位置的num找到了正確的位置,它的左邊都是比它小的以及和它一樣的數(shù),右邊都是比它大的數(shù)
- 回到1,進(jìn)行遞歸或迭代,使得所有的數(shù)都找到正確的位
二.通過(guò)荷蘭國(guó)旗問(wèn)題改進(jìn)快排
什么是荷蘭國(guó)旗問(wèn)題?
已知一個(gè)整形數(shù)組arr,和一個(gè)整數(shù)num,請(qǐng)把小于num的數(shù)放在數(shù)組的左邊,等于num的數(shù)放在數(shù)組的中間,大于num的數(shù)放在數(shù)組的右邊。
解決思路:
遍歷數(shù)組
- 1. 若比num小,當(dāng)前位置和小于的最后一個(gè)位置+1的值交換,并當(dāng)前位置++;
- 2. 若比num大,當(dāng)前位置和大于的第一個(gè)位置-1的值交換;
- 3. 若等于num的值,當(dāng)前位置++;
附上代碼:
public static void NetherlandsFlag(int[] arr, int L, int R, int num) {
int i = L;
int p1 = L-1;
int p2 = R+1;
//終止條件:當(dāng)前數(shù)的位置在大于區(qū)的前一個(gè)
while(i < p2) {
if(arr[i] < num) {
//當(dāng)前數(shù)比num小,放左邊,i位置上的數(shù)和L上的數(shù)進(jìn)行交換,并且i++,L++
swap(arr, i++, ++p1);
} else if(arr[i] == num) {
//當(dāng)前數(shù)和num相等,i++
i++;
} else {
//當(dāng)前數(shù)比num大,放右邊,i位置上的數(shù)和R上的數(shù)進(jìn)行交換,并且i++,R--
swap(arr, i, --p2);
}
}
}
我們可以發(fā)現(xiàn),荷蘭國(guó)旗問(wèn)題和經(jīng)典快排不同的就只是將<=num改為了< num和=num兩部分,借用這個(gè)思想使得原來(lái)每次只可以讓一個(gè)數(shù)找到正確的位置改進(jìn)為了每次至少讓一個(gè)數(shù)找到位置。
三.在這基礎(chǔ)上將其改為隨機(jī)快排
隨機(jī)快排改進(jìn)的地方只是在選取數(shù)的時(shí)候,將每次都選取最后位置的數(shù)改為選取隨機(jī)的一個(gè)數(shù)作為num,這樣做的好處是什么呢?
1.選取最后一個(gè)數(shù):如果是一個(gè)已經(jīng)排好序的數(shù)組,每次找到位置之后,左邊是要進(jìn)行排序的部分,數(shù)組長(zhǎng)度是原長(zhǎng)度-1,它的時(shí)間復(fù)雜度就是O(N^2);如果每次找到的數(shù)都是中間的位置,它的時(shí)間復(fù)雜度就只有O(logN)
2.然而以隨機(jī)數(shù)作為選取的標(biāo)準(zhǔn)num的時(shí)候,因?yàn)槭请S機(jī)的,就只能通過(guò)數(shù)學(xué)期望去計(jì)算它的時(shí)間復(fù)雜度,時(shí)間復(fù)雜度是O(logN)
下面附上最終的快排代碼及注釋
/*
* swap(int[] arr, int i, int j);是將arr數(shù)組的i和j位置上的數(shù)交換的方法
*/
public static void quickSort(int[] arr) {
// 如果為空或長(zhǎng)度為1不需要排序,直接返回
if(arr == null || arr.length < 2)
return;
else
quickSort(arr, 0, arr.length - 1);
}
// 遞歸排序
public static void quickSort(int[] arr, int L, int R) {
if(L < R) {
/*
* 隨機(jī)快排的隨機(jī)就在這
* 是隨機(jī)選取了一個(gè)數(shù),和 R 進(jìn)行了交換,然后使用這個(gè)數(shù)作為num,
* 所以每次選取的num是隨機(jī)的,
* 在計(jì)算時(shí)間復(fù)雜度時(shí),是沒(méi)有最優(yōu)最差情況的
* 而是通過(guò)一個(gè)長(zhǎng)期的數(shù)學(xué)期望計(jì)算的,結(jié)果是O(N*logN)
*/
swap(arr, L + (int) (Math.random() * (R - L + 1)), R);
int[] border = partition(arr, L, R);
// 小于區(qū)和大于區(qū)進(jìn)行遞歸
quickSort(arr, L, border[0] - 1);
quickSort(arr, border[1] + 1, R);
}
}
// 將給定數(shù)組劃分為小于區(qū)、等于區(qū)和大于區(qū)
public static int[] partition(int[] arr, int L, int R) {
int num = arr[R];
int less = L - 1;
int more = R + 1;
int curr = L;
// 分為小于區(qū)等于區(qū)和大于區(qū)
while(curr < more) {
if(arr[curr] < num) {
swap(arr, curr++, ++less);
} else if(arr[curr] > num) {
swap(arr, curr, --more);
} else {
curr++;
}
}
//返回等于區(qū)的左右邊界的下標(biāo),通過(guò)下標(biāo)確定小于區(qū)和大于區(qū)遞歸時(shí)的參數(shù)
return new int[] {less + 1, more - 1};
}
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接
- Java排序算法之堆排思想及代碼實(shí)現(xiàn)
- Java二叉樹(shù)的遍歷思想及核心代碼實(shí)現(xiàn)
- 原生javascript實(shí)現(xiàn)連連看游戲
- Java計(jì)算器核心算法代碼實(shí)現(xiàn)
- JavaScript鍵盤事件常見(jiàn)用法實(shí)例分析
- Java語(yǔ)言實(shí)現(xiàn)非遞歸實(shí)現(xiàn)樹(shù)的前中后序遍歷總結(jié)
- 淺談Java 8 新增函數(shù)式接口到底是什么
- JavaScript實(shí)現(xiàn)動(dòng)態(tài)添加、移除元素或?qū)傩缘姆椒ǚ治?/a>
- Java多邊形重心計(jì)算
- java連連看游戲菜單設(shè)計(jì)
相關(guān)文章
Mybatis + js 實(shí)現(xiàn)下拉列表二級(jí)聯(lián)動(dòng)效果
這篇文章給大家介紹基于Mybatis + js 實(shí)現(xiàn)下拉列表二級(jí)聯(lián)動(dòng)效果,實(shí)現(xiàn)代碼分為前端界面實(shí)現(xiàn)和后端處理方法,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-06-06
關(guān)于swagger配置及踩坑@Api參數(shù)postion無(wú)效解決接口排序問(wèn)題
這篇文章主要介紹了關(guān)于swagger配置及踩坑@Api參數(shù)postion無(wú)效解決接口排序問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
Java中靜態(tài)類型檢查是如何進(jìn)行的實(shí)例思路詳解
這篇文章主要介紹了Java中靜態(tài)類型檢查是如何進(jìn)行的實(shí)例思路詳解的相關(guān)資料,需要的朋友可以參考下2016-05-05
解決使用@Value(${×××))從properties文件取值的坑
這篇文章主要介紹了解決使用@Value(${×××))從properties文件取值的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
深入理解Mybatis中的resultType和resultMap
這篇文章給大家介紹了mybatis中的resultType和resultMap的用法實(shí)例講解,MyBatis中在查詢進(jìn)行select映射的時(shí)候,返回類型可以用resultType,也可以用resultMap,至于兩種用法區(qū)別,通過(guò)本文一起學(xué)習(xí)吧2016-09-09
Hibernate懶加載之<class>標(biāo)簽上的lazy
這篇文章主要介紹了Hibernate懶加載之<class>標(biāo)簽上的lazy,分享了相關(guān)代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-02-02
深入理解Java8新特性之Optional容器類的應(yīng)用
Optional<T> 類(java.util.Optional) 是一個(gè)容器類,代表一個(gè)值存在或不存在,原來(lái)用 null 表示一個(gè)值不存在,現(xiàn)在 Optional 可以更好的表達(dá)這個(gè)概念。并且可以避免空指針異常,需要的朋友可以參考下本文2021-11-11

