常见的算法排序(2)
?前言?
📘 博客主頁:to Keep博客主頁
🙆歡迎關(guān)注,👍點(diǎn)贊,📝留言評論
?首發(fā)時間:2022年3月1日
📨 博主碼云地址:博主碼云地址
📕參考書籍:java核心技術(shù) 卷1
📢編程練習(xí):牛客網(wǎng)+力扣網(wǎng)
由于博主目前也是處于一個學(xué)習(xí)的狀態(tài),如有講的不對的地方,請一定聯(lián)系我予以改正!!!
文章目錄
- 🚄1 快速排序
- 🚅1.1 快排原理
- 🚈1.2 遞歸實(shí)現(xiàn)
- 🚝1.3 對快排進(jìn)行優(yōu)化(三數(shù)取中法)
- 🚃1.4 非遞歸實(shí)現(xiàn)
- 🚋二 歸并排序
- 🚌2.1 歸并的核心思想
- 🚎2.2 歸并排序的遞歸實(shí)現(xiàn)
- 🚍2.3 歸并排序的非遞歸實(shí)現(xiàn)
- 🚗三 其他排序(非基于比較)
- 🚖3.1 計數(shù)排序
- 🚘3.2 基數(shù)排序
- 🚔3.3 桶排序
- 🚉4 總結(jié)
🚄1 快速排序
🚅1.1 快排原理
1 從待排序區(qū)間選擇一個數(shù),作為基準(zhǔn)值
2 遍歷整個待排序區(qū)間,將比基準(zhǔn)值小的(可以包含相等的)放到基準(zhǔn)值的左邊,將比基準(zhǔn)值大的(可以包含相等的)放到基準(zhǔn)值的右邊;
3 采用分治思想對左右兩個小區(qū)間,對左右兩個小區(qū)間按照同樣的方式來處理,直到小區(qū)間的長度==1,那么表面已經(jīng)有序,如果長度為零,則說明沒有數(shù)據(jù)!
🚈1.2 遞歸實(shí)現(xiàn)
通過了解快排的原理,那么就可以編寫如下代碼(我們一開始以數(shù)列中第一個數(shù)為基準(zhǔn)值,尋找基準(zhǔn)在數(shù)列中所在的位置):
public class TestDemo1 {public static void main(String[] args) {int[] array = {67,7,32,98,1,0,45,23,234,6746,123};Quack(array);System.out.println(Arrays.toString(array));}/*** 快排遞歸寫法* 時間復(fù)雜度: 最好 O(N*logN) 最差(有序) O(N*N)* 空間復(fù)雜度: O(logN) * 穩(wěn)定性:不穩(wěn)定* @param array 待排序數(shù)列*/public static void Quack(int[] array){QuackSort(array,0,array.length-1);}public static void QuackSort(int[] array,int left,int right){//遞歸的終止條件,當(dāng)左等于大于右時,說明此時序列有序if(left>=right){return;}//找基準(zhǔn)int privot = getprivot(array,left,right);//遞歸左邊QuackSort(array,left,privot-1);//遞歸右邊QuackSort(array,privot+1,right);}public static int getprivot(int[] array,int start,int end){int tmp = array[start];while (start<end){while (start<end&&array[end]>=tmp){end--;}array[start]=array[end];while (start<end&&array[start]<=tmp){start++;}array[end]=array[start];}array[start]=tmp;return start;} }🚝1.3 對快排進(jìn)行優(yōu)化(三數(shù)取中法)
對于快排的優(yōu)化,其實(shí)就是優(yōu)化基準(zhǔn):
public class TestDemo1 {public static void main(String[] args) {int[] array = {67,7,32,98,1,0,45,23,234,6746,123};Quack(array);System.out.println(Arrays.toString(array));}/*** 快排遞歸寫法* 時間復(fù)雜度: 最好 O(N*logN) 最差(有序) O(N*N)* 空間復(fù)雜度: O(logN)* 穩(wěn)定性:不穩(wěn)定* @param array*/public static void Quack(int[] array){QuackSort(array,0,array.length-1);}public static void Swap(int[] array,int i,int j){int tmp = array[i];array[i]=array[j];array[j]=tmp;}public static int getMid(int[] array,int a,int b){int mid = a+((b-a)>>>1);if(array[a]>array[b]){if(array[mid]>array[a]){return a;}else if(array[mid]<array[b]){return b;}else{return mid;}}else{//array[a]<array[b]if(array[mid]<array[a]){return a;}else if(array[mid]>array[b]){return b;}else{return mid;}}}public static void QuackSort(int[] array,int left,int right){//遞歸的終止條件,當(dāng)左等于大于右時,說明此時序列有序if(left>=right){return;}//獲取三個值中間值的小標(biāo)int mid = getMid(array,left,right);//在把中間值放到一開始的位置Swap(array,left,mid);//找基準(zhǔn)int privot = getprivot(array,left,right);//遞歸左邊QuackSort(array,left,privot-1);//遞歸右邊QuackSort(array,privot+1,right);}public static int getprivot(int[] array,int start,int end){int tmp = array[start];while (start<end){while (start<end&&array[end]>=tmp){end--;}array[start]=array[end];while (start<end&&array[start]<=tmp){start++;}array[end]=array[start];}array[start]=tmp;return start;} }優(yōu)化總結(jié):
1 快排的優(yōu)化實(shí)質(zhì)上就是在對基準(zhǔn)進(jìn)行優(yōu)化,所以這里采用了三數(shù)取中法進(jìn)行優(yōu)化
2 可以結(jié)合我們之前所學(xué)的直接插入排序進(jìn)行優(yōu)化,對于插入排序,之前已經(jīng)了解到數(shù)列越有序越快,那么就可以當(dāng)調(diào)整的長度小于某個數(shù)的時候,可以直接利用直接插入排序
🚃1.4 非遞歸實(shí)現(xiàn)
對于非遞歸的實(shí)現(xiàn),我們此時還是一樣根據(jù)原理需要找到基準(zhǔn)值,然后再利用數(shù)據(jù)結(jié)構(gòu)中棧去解決(核心的思想也是利用找基準(zhǔn)去解決):
代碼如下:
🚋二 歸并排序
🚌2.1 歸并的核心思想
給定兩個有序數(shù)組,那么如何將他們合并成為一個有序的數(shù)組呢?其實(shí)在合并的過程中就體現(xiàn)出歸并排序的初步思想原理,就是依據(jù)這樣的一個思想。
代碼如下:
🚎2.2 歸并排序的遞歸實(shí)現(xiàn)
public static void mergeSort(int[] array){merge(array,0,array.length-1);}public static void merge(int[] array,int low,int high){int mid = low+((high-low)>>>1);//遞歸的終止條件if(low>=high){return;}//左邊遞歸進(jìn)行分解merge(array,low,mid);//右邊遞歸進(jìn)行分解merge(array,mid+1,high);//開始?xì)w并Conbine(array,low,mid,high);}//歸并的核心思想public static void Conbine(int[] array,int low,int mid,int high){int[] tmp = new int[high-low+1];int i = 0;int s1 = low;int e1 = mid;int s2 = mid+1;int e2 = high;while (s1<=e1&&s2<=e2){while (s1<=e1&&s2<=e2){if(array[s1]<array[s2]){tmp[i++]=array[s1++];}else{tmp[i++]=array[s2++];}}//可能存在第一個數(shù)組沒放完或者第二個數(shù)組的數(shù)據(jù)沒放完while (s1<=e1){tmp[i++]=array[s1++];}while (s2<=e2){tmp[i++]=array[s2++];}}for (int j = 0; j < i; j++) {//注意數(shù)組下標(biāo),當(dāng)遇到右邊數(shù)組合并時,它的第一個下標(biāo)已經(jīng)不是零了array[j+low]=tmp[j];}}🚍2.3 歸并排序的非遞歸實(shí)現(xiàn)
非遞歸排序,所采用的思想就是先分組,先是一個一個一組,在變成兩個一組,最后整個數(shù)組為一組時,此時就是一個有序的數(shù)組。
public static void nonmergeSort(int[] array){//組數(shù)(一開始一個一組)int gap = 1;//只有組數(shù)大于等于數(shù)組的長度,那么此時說明數(shù)組已經(jīng)有序while (gap<array.length){//每重新分組,遍歷一遍數(shù)組,進(jìn)行歸并排序for (int i = 0; i < array.length-1; i+=2*gap) {int left = i;int mid = left+gap-1;//注意這時mid可能會越界if (mid>=array.length){mid=array.length-1;}int right = mid+gap;if(right>=array.length){right=array.length-1;}//開始?xì)w并Conbine(array,left,mid,right);}//循環(huán)結(jié)束,組數(shù)乘2gap=gap*2;}}public static void Conbine(int[] array,int low,int mid,int high){int[] tmp = new int[high-low+1];int i = 0;int s1 = low;int e1 = mid;int s2 = mid+1;int e2 = high;while (s1<=e1&&s2<=e2){while (s1<=e1&&s2<=e2){if(array[s1]<array[s2]){tmp[i++]=array[s1++];}else{tmp[i++]=array[s2++];}}//可能存在第一個數(shù)組沒放完或者第二個數(shù)組的數(shù)據(jù)沒放完while (s1<=e1){tmp[i++]=array[s1++];}while (s2<=e2){tmp[i++]=array[s2++];}}for (int j = 0; j < i; j++) {//注意數(shù)組下標(biāo),當(dāng)遇到右邊數(shù)組合并時,它的第一個下標(biāo)已經(jīng)不是零了array[j+low]=tmp[j];}}🚗三 其他排序(非基于比較)
🚖3.1 計數(shù)排序
計數(shù)排序詳解
🚘3.2 基數(shù)排序
基數(shù)排序詳解
🚔3.3 桶排序
桶排序詳解
🚉4 總結(jié)
可以通過一個表格列舉出這些排序的特點(diǎn),根據(jù)排序的需求,選擇合適的排序方式!
總結(jié)
以上是生活随笔為你收集整理的常见的算法排序(2)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 常见的排序算法(1)
- 下一篇: 源码必备知识:泛型