非科班面試之旅:Java實現資料結構中的八種排序方法
阿新 • • 發佈:2021-08-09
非科班面試之旅:Java實現資料結構中的八種排序方法
-
@return
*/
public int partition(int[] data, int low, int high){
getPivot(data, low, high); int pivot = data[high-1];//樞軸元素 int i = low; int j = high - 1; while(i < j){ while(i < j && data[++i] <= pivot){} data[j] = data[i];//data[i]大於pivot,移到後半區,此時原data[j]的值已儲存在pivot或data[i]中 while(i < j && data[--j] >= pivot){} data[i] = data[j];//data[j]小於pivot,移到前半區,此時原data[i]的值已儲存在data[j]中 } data[i] = pivot; return i;
}
/**
-
取首、中、尾三者中間大小元素,避免快速排序效能退化
-
@param data
-
@param low
-
@param high
*/
public void getPivot(int[] data, int left, int right){
int mid = (left + right) / 2; //對三個元素按遞增排序 if (data[left] > data[mid]) { swap(data, left, mid); } if (data[left] > data[right]) { swap(data, left, right); } if (data[right] < data[mid]) { swap(data, right, mid); } //將樞軸元素放置在待排序陣列後 swap(data, right-1, mid);
}
/**
-
快速排序非遞迴
-
@param data
*/
public void quickSortNotRecur(int[] data, int low, int high){
//使用棧來實現遞迴的壓棧出棧操作 Stack<Object> s = new Stack<Object>(); s.push(low); s.push(high); if(!s.empty()){ high = (Integer) s.pop(); low = (Integer) s.pop(); int loc = partition(data, low, high);//進行一次分割槽 s.push(loc+1);//後半區先進後出 s.push(high); s.push(low);//前半區後進先出 s.push(loc-1); }
}
-
[](https://gitee.com/vip204888/java-p7)6、堆排序
-----------------------------------------------------------------------
對待排列的n個元素組成的序列,將其看成一個完全二叉樹,如果該二叉樹中的任一非葉子節點的值均不小於(不大於)其左右子樹節點,則該二叉樹稱為大根堆(小根堆),樹的根節點(堆頂元素)是序列中最大(最小)的元素。
堆排序的基本思想是:對待非遞減排列的序列首先建立一個初始堆,此時輸出堆頂元素,即最大值元素,然後取最後一個葉子節點替代堆頂元素,並將剩下的元素重新構建為大根堆,再輸出新堆的堆頂元素作為次大值元素…以此類推,直到所有的元素有序排列。
![堆排序](https://img-blog.csdnimg.cn/5abb79842dd9427e8832e59d43247cac.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NpbmF0XzM3NjIzNDkw,size_16,color_FFFFFF,t_70)
/**
* 堆排序
* @param data
*/
public void heapSort(int[] data){
int i, n, tmp;
n = data.length;
for(i=n/2-1;i>=0;i--){//從n位置子節點所在子樹開始向上調整整個陣列為大根堆(構建初始堆)
heapAdjust(data, i, n-1);
}
for(i=n-1;i>0;i--){//從初始堆取堆頂(最大元素),對剩餘元素重新構建大根堆
tmp = data[0];//取堆頂
data[0] = data[i];//將最末尾子節點交換到堆頂
data[i] = tmp;//當前最大值放到陣列末尾
heapAdjust(data, 0, i-1);//剩餘i-1個元素構建大根堆
}
System.out.println(Arrays.toString(data));
}
/**
* 將待排序元素調整為大根堆
* @param data
* @param s
* @param m
*/
public void heapAdjust(int[] data, int s, int m){
int i, tmp;
tmp = data[s];//備份當前父節點關鍵字
for(i=2*s+1;i<=m;i=2*i+1){
if(i<m && data[i]<data[i+1]){//找到子節點中關鍵字最大者
i++;
}
if(tmp>=data[i]) break; //所有子節點都不大於父節點,本次無需調整
data[s] = data[i]; //存在比父節點大的子節點,插入s位置
s = i; //以i作為父節點的子樹可能因為本次調整不再是大根堆,因此需要進行調整
}
data[s] = tmp;//將備份關鍵字插入最後做了交換的節點位置
}
[](https://gitee.com/vip204888/java-p7)7、歸併排序
------------------------------------------------------------------------
歸併排序的一種實現方法是把一個有n個記錄的無序檔案看成是由n個長度為1的有序子檔案組成的檔案,對子檔案兩兩歸併,得到n/2個長度為2或1的有序檔案,再兩兩歸併,重複得到一個包含n個記錄的有序檔案。
![歸併排序](https://img-blog.csdnimg.cn/849a5694e2a8463f88f6cfd704ec2a8d.png)
假設一次歸併的兩個檔案為陣列arr1和陣列arr2,則需要一個大小為arr1和arr2長度之和的輔助空間arrTmp來進行歸併,此時三個指標分別指向arr1,arr2和arrTmp初始位置,每次對比arr1和arr2指標指向元素,將其中較小值插入到arrTmp指標所指位置。當arr1,arr2中任一陣列末尾元素插入到了arrTmp中,則將另一個數組剩餘元素直接全部插入arrTmp中即可。如下圖所示:
![藉助輔助陣列進行歸併](https://img-blog.csdnimg.cn/735654007c6141d9a331c0608d4564c3.png)
/**
* 歸併排序
* @param data
* @param s
* @param t
*/
public void mergeSort(int[] data, int left, int right){
if(left < right){
int mid = (left + right) >> 1;
mergeSort(data, left, mid);//前半區歸併得到有序子序列data[left..mid]
mergeSort(data, mid + 1, right);//後半區歸併得到有序子序列data[mid..right]
merge(data, left, mid, right);//data[left..mid]和data[mid..right]歸併得到有序的data[s..t]
}
}
/**
* 對兩個序列data[s..m]和data[m+1..n]進行歸併
* @param data
* @param s
* @param m
* @param n
*/
public void merge(int[] data, int s, int m, int n){
int i = s, j = m + 1, k = 0;//i指向data[m+1..n]初始位置,j指向data[s..m]初始位置,k指向tmp[]初始位置
int st = s;
int[] tmp = new int[data.length];
while(i<=m&&j<=n){//歸併data[s..m]和data[m+1..n]存入臨時陣列tmp[]
if(data[i]<=data[j]){
tmp[k++] = data[i++];
}else{
tmp[k++] = data[j++];
}
}
for(;i<=m;i++){//將剩餘data[s..m]元素複製到tmp[]
tmp[k++] = data[i];
}
for(;j<=n;j++){//將剩餘data[m+1..n]元素複製到tmp[]
tmp[k++] = data[j];
}
for(i=0;i<k;i++){//將臨時陣列元素複製回原陣列
data[st++] = tmp[i];
}
//用於輸出資訊
if(s == 0 && n == data.length-1 >> 1){
System.out.println("前半區歸併完成:" + Arrays.toString(data));
}
if(s == data.length >> 1 && n == data.length - 1){
System.out.println("後半區歸併完成:" + Arrays.toString(data));
}
}
[](https://gitee.com/vip204888/java-p7)8、基數排序
------------------------------------------------------------------------
基數排序是一種通過比較元素各個位數大小來進行排序的方法:基數r是按照元素數值的進位制來確定的,比如十進位制r=10,八進位制則r=8。d原來表示元素的位數,d取所有待排序元素的位數最大值,比如125則d=3。
進行基數排序時,設立r個佇列,佇列編號分別從0到r-1。首先按照最低有效位大小將元素分別排進佇列中,然後按照佇列中的順序將元素重新排列。接著按照次低有效位將重新排列好的元素再次排進佇列中…如此重複直到最高有效位完成排列,此時從佇列取出的元素有序排列。
![基數排序](https://img-blog.csdnimg.cn/f0eefaabf8e648eba0be16f8092bb304.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NpbmF0XzM3NjIzNDkw,size_16,color_FFFFFF,t_70)
/**
* 基數排序
* @param data
*/
public void radixSort(int[] data){
//確定最大位數
int max = data[0];
for(int x: data){
if(x > max){
max = x;
}
}
int length = (max+"").length();
for(int i=0,n=1;i<length;i++,n*=10){
int[][] tmp = new int[10][data.length];
int[] queLength = new int[10];//儲存每個佇列入隊元素個數
//將陣列元素一一入隊
for(int x: data){
int index = x / n % 10;//確定元素應入佇列
tmp[index][queLength[index]++] = x;
}
//將佇列中元素重新排列為陣列
int dataIdx = 0;
for(int j=0;j<10;j++){
for(int q=0;q<queLength[j];q++){
data[dataIdx++] = tmp[j][q];
}
}
}
System.out.println(Arrays.toString(data));
}
[](https://gitee.com/vip204888/java-p7)執行例項
----------------------------------------------------------------------
import java.util.Arrays;
import java.util.Stack;
public class Sort {
final int[] data = {76,34,18,12,45,5,5,9};
public static void main(String args[]){
Sort sort1 = new Sort();
System.out.print("**直接插入排序\n原陣列:" + Arrays.toString(sort1.data) + "\n排序後:");
sort1.insertSort(sort1.data);
Sort sort2 = new Sort();
System.out.print("\n**氣泡排序\n原陣列:" + Arrays.toString(sort2.data) + "\n排序後:");
sort2.bubbleSort(sort2.data);
Sort sort3 = new Sort();
System.out.print("\n**簡單選擇排序\n原陣列:" + Arrays.toString(sort3.data) + "\n排序後:");
sort3.selectSort(sort3.data);
Sort sort4 = new Sort();
System.out.print("\n**希爾排序\n原陣列:" + Arrays.toString(sort4.data) + "\n");
sort4.shellSort(sort4.data);
Sort sort5 = new Sort();
System.out.print("\n**快速排序\n原陣列:" + Arrays.toString(sort5.data) + "\n排序後:");
sort4.quickSort(sort5.data, 0, sort5.data.length - 1);
System.out.println(Arrays.toString(sort5.data));
Sort sort51 = new Sort();
System.out.print("\n**快速排序(非遞迴)\n原陣列:" + Arrays.toString(sort51.data) + "\n排序後:");
sort4.quickSort(sort51.data, 0, sort51.data.length - 1);
System.out.println(Arrays.toString(sort51.data));
Sort sort6 = new Sort();
System.out.print("\n**堆排序\n原陣列:" + Arrays.toString(sort6.data) + "\n排序後:");
sort4.heapSort(sort6.data);
Sort sort7 = new Sort();
System.out.println("\n**歸併排序\n原陣列:" + Arrays.toString(sort7.data));
sort4.mergeSort(sort7.data, 0, sort7.data.length - 1);
System.out.println("排序後:" + Arrays.toString(sort7.data));
Sort sort8 = new Sort();
System.out.print("\n**基數排序\n原陣列:" + Arrays.toString(sort8.data) + "\n排序後:");
sort4.radixSort(sort8.data);
}
public void swap(int[] data, int i, int j){
int tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
}
輸出結果:
> \*\*直接插入排序
> 原陣列:\[76, 34, 18, 12, 45, 5, 5, 9\]
> 排序後:\[5, 5, 9, 12, 18, 34, 45, 76\]
>
> \*\*氣泡排序
> 原陣列:\[76, 34, 18, 12, 45, 5, 5, 9\]
> 排序後:\[5, 5, 9, 12, 18, 34, 45, 76\]
>
> \*\*簡單選擇排序
> 原陣列:\[76, 34, 18, 12, 45, 5, 5, 9\]
> 排序後:\[5, 5, 9, 12, 18, 34, 45, 76\]
>
> \*\*希爾排序
> 原陣列:\[76, 34, 18, 12, 45, 5, 5, 9\]
> 分組間距:4,此次排序得到:
> \[45, 5, 5, 9, 76, 34, 18, 12\]
> 分組間距:2,此次排序得到:
> \[5, 5, 18, 9, 45, 12, 76, 34\]
> 分組間距:1,此次排序得到:
> \[5, 5, 9, 12, 18, 34, 45, 76\]
>
## 最後:學習總結——MyBtis知識腦圖(純手繪xmind文件)
學完之後,若是想驗收效果如何,其實最好的方法就是可自己去總結一下。比如我就會在學習完一個東西之後自己去手繪一份xmind檔案的知識梳理大綱腦圖,這樣也可方便後續的複習,且都是自己的理解,相信隨便瞟幾眼就能迅速過完整個知識,腦補回來。下方即為我手繪的MyBtis知識腦圖,由於是xmind檔案,不好上傳,所以小編將其以圖片形式匯出來傳在此處,細節方面不是特別清晰。但可給感興趣的朋友提供完整的MyBtis知識腦圖原件(包括上方的面試解析xmind文件)
![image](https://upload-images.jianshu.io/upload_images/24613101-cca28b670ec32761.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
除此之外,前文所提及的Alibaba珍藏版mybatis手寫文件以及一本小小的MyBatis原始碼分析文件——《MyBatis原始碼分析》等等相關的學習筆記文件,也皆可分享給認可的朋友!
**[資料領取方式:戳這裡免費下載](https://gitee.com/vip204888/java-p7)**