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