Java實現(xiàn)歸并排序的方法詳解(包含遞歸+非遞歸)
歸并排序是分治思想的經(jīng)典實現(xiàn),核心是:拆分?jǐn)?shù)組→合并有序子數(shù)組。 時間復(fù)雜度:O(n log n),空間復(fù)雜度:O(n),穩(wěn)定排序。
下面直接給你可直接運行的 Java 代碼,包含遞歸版和非遞歸(迭代)版。
1. 遞歸版歸并排序(最常用)
思路:
- 把數(shù)組從中間拆分成左右兩部分
- 遞歸排序左右子數(shù)組
- 合并兩個有序子數(shù)組為一個有序數(shù)組
public class MergeSort {
// 對外暴露的排序方法
public static void mergeSort(int[] arr) {
if (arr == null || arr.length <= 1) {
return;
}
// 臨時數(shù)組,避免遞歸中頻繁創(chuàng)建數(shù)組
int[] temp = new int[arr.length];
sort(arr, 0, arr.length - 1, temp);
}
// 遞歸拆分 + 排序
private static void sort(int[] arr, int left, int right, int[] temp) {
// 遞歸終止條件:子數(shù)組只有一個元素
if (left >= right) {
return;
}
int mid = left + (right - left) / 2; // 防止溢出
sort(arr, left, mid, temp); // 排序左半部分
sort(arr, mid + 1, right, temp); // 排序右半部分
merge(arr, left, mid, right, temp); // 合并兩個有序子數(shù)組
}
// 合并兩個有序區(qū)間 [left, mid] 和 [mid+1, right]
private static void merge(int[] arr, int left, int mid, int right, int[] temp) {
int i = left; // 左數(shù)組起始指針
int j = mid + 1; // 右數(shù)組起始指針
int k = left; // 臨時數(shù)組指針
// 把兩個有序子數(shù)組按順序放入 temp
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
// 拷貝左數(shù)組剩余元素
while (i <= mid) {
temp[k++] = arr[i++];
}
// 拷貝右數(shù)組剩余元素
while (j <= right) {
temp[k++] = arr[j++];
}
// 把 temp 中排好序的部分復(fù)制回原數(shù)組
System.arraycopy(temp, left, arr, left, right - left + 1);
}
// 測試
public static void main(String[] args) {
int[] arr = {8, 4, 5, 7, 1, 3, 6, 2};
System.out.println("排序前:");
for (int num : arr) {
System.out.print(num + " ");
}
mergeSort(arr);
System.out.println("\n遞歸歸并排序后:");
for (int num : arr) {
System.out.print(num + " ");
}
}
}
2. 非遞歸版歸并排序(迭代實現(xiàn))
思路:
- 從最小子數(shù)組長度 = 1開始,兩兩合并
- 子數(shù)組長度翻倍(1→2→4→8…)
- 直到合并成整個數(shù)組 無遞歸,避免棧溢出,適合大數(shù)據(jù)量
public class MergeSortNonRecursive {
public static void mergeSortNonRecursive(int[] arr) {
if (arr == null || arr.length <= 1) {
return;
}
int n = arr.length;
int[] temp = new int[n];
int mergeSize = 1; // 初始合并單元長度:1
while (mergeSize < n) {
// 每次從左到右依次合并兩個長度為 mergeSize 的子數(shù)組
for (int left = 0; left < n; left += mergeSize * 2) {
int mid = left + mergeSize - 1;
// 右邊界不能越界
int right = Math.min(left + mergeSize * 2 - 1, n - 1);
// 只有左半邊,無需合并
if (mid >= right) {
break;
}
// 合并邏輯和遞歸版完全一樣
merge(arr, left, mid, right, temp);
}
// 子數(shù)組長度翻倍
mergeSize *= 2;
}
}
// 合并方法和遞歸版完全相同
private static void merge(int[] arr, int left, int mid, int right, int[] temp) {
int i = left;
int j = mid + 1;
int k = left;
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
while (i <= mid) {
temp[k++] = arr[i++];
}
while (j <= right) {
temp[k++] = arr[j++];
}
System.arraycopy(temp, left, arr, left, right - left + 1);
}
// 測試
public static void main(String[] args) {
int[] arr = {8, 4, 5, 7, 1, 3, 6, 2};
System.out.println("排序前:");
for (int num : arr) {
System.out.print(num + " ");
}
mergeSortNonRecursive(arr);
System.out.println("\n非遞歸歸并排序后:");
for (int num : arr) {
System.out.print(num + " ");
}
}
}
核心說明
- merge 方法 兩個版本的合并邏輯完全相同,是歸并排序的核心。
- 遞歸 vs 非遞歸
- 遞歸:代碼簡潔,易理解,大數(shù)據(jù)量可能棧溢出
- 非遞歸:無棧溢出風(fēng)險,效率更穩(wěn)定
- 穩(wěn)定性 相等元素不交換順序,是穩(wěn)定排序。
總結(jié)
- 遞歸版:自上而下拆分,代碼簡潔,適合學(xué)習(xí)理解
- 非遞歸版:自下而上合并,無棧溢出,適合生產(chǎn)環(huán)境
- 兩個版本時間復(fù)雜度都是 O (n log n),都需要 O (n) 臨時空間
- 復(fù)制代碼可直接運行,輸出排序結(jié)果
以上就是Java實現(xiàn)歸并排序的方法詳解(包含遞歸+非遞歸)的詳細(xì)內(nèi)容,更多關(guān)于Java實現(xiàn)歸并排序的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java如何通過modbus4j實現(xiàn)modbus?TCP通訊
Modbus協(xié)議包含RTU、ASCII、TCP三種類型,定義四個存儲區(qū)(輸出線圈、輸入線圈、輸出寄存器、輸入寄存器)及其地址范圍,支持讀寫功能,通過功能碼01-04操作,仿真軟件可模擬從站ID2025-07-07
Spring超詳細(xì)講解創(chuàng)建BeanDefinition流程
Spring在初始化過程中,將xml中定義的對象解析到了BeanDefinition對象中,我們有必要了解一下BeanDefinition的內(nèi)部結(jié)構(gòu),有助于我們理解Spring的初始化流程2022-06-06
idea導(dǎo)入module的正確實現(xiàn)方法
文章介紹了在IntelliJ IDEA中正確導(dǎo)入Spring Cloud項目module的方法:通過File→New→Module from Existing Sources選擇路徑并點擊OK,隨后右擊pom.xml添加為Maven項目,最后運行Maven Install生命周期完成編譯,強調(diào)操作步驟的重要性,避免因失誤導(dǎo)致問題2025-07-07
解決MyBatis中模糊搜索使用like匹配帶%字符時失效問題
Mybatis是我們?nèi)粘m椖恐薪?jīng)常使用的框架,在項目中我們一般會使用like查詢作為模糊匹配字符進(jìn)行搜索匹配,下面的Mapper.xml是我們使用like在項目中進(jìn)行模糊匹配的常用方式,感興趣的朋友跟隨小編一起看看吧2021-09-09
java實現(xiàn)導(dǎo)出數(shù)據(jù)為zip壓縮文件
這篇文章主要為大家詳細(xì)介紹了java如何實現(xiàn)導(dǎo)出數(shù)據(jù)為zip壓縮文件,并且解壓后為json文件,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-11-11
Java線程和操作系統(tǒng)線程的關(guān)系解讀
這篇文章主要介紹了Java線程和操作系統(tǒng)線程的關(guān)系解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06

