前言
归并排序,其实不难,捋清楚思路,把握他的核心思想:先分组后排序。
以下是我的个人理解和实现,希望对读者有帮助。
个人理解
我认为的归并排序,就是先分组后排序,具体来说,
分组 就是给你一个数组,你把它分组,分成每个元素都是一个组,例如:8个人,编号是从0~7,那么我们就把他们分成8组,然后在进行归并。关于这部分的实现:我用的是递归,就是我代码中的msort
归并:在分组完成的基础上,我们要将这些组合并起来,从 8 个组变成 1 个组,就完成了归并。采用的方式是两两比较,拿第一个组的第一个元素,和第二组的第一个元素,进行比较,将比较小的放到我们定义的临时数组里,聪明的人应该看出来了,这样比较的话,肯定会有一个组的元素率先用完,那样我们就把那个组剩余的元素,直接放进去就可以了。
关于这部分的实现,就是我代码中的merge方法
package data_structure;
import java.util.Arrays;
// 归并排序
public class IArraySort {
public static void main(String[] args) {
int[] arr = {3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48};
System.out.println("归并前的数组" + Arrays.toString(arr));
mergeSort(arr, arr.length);
System.out.println("归并后的数组" + Arrays.toString(arr));
}
// 归并入口
private static void mergeSort(int[] arr, int n) {
// 定义一个临时数组
int[] tempArr = new int[n];
// 归并排序
msort(arr, tempArr, 0, n - 1);
}
// 分组,把整个数组分成每个元素成为一组
private static void msort(int[] arr, int[] tempArr, int left, int right) {
// 如果只有一个元素,,那么就不需要进行排序了
// 因为只有一个元素的区域,本来就是有序区域
// 所以只有当左边小于右边时才需要分组
if (left < right) {
// 找中间点
int mid = (left + right) / 2;
// 递归划分左半区域
msort(arr, tempArr, left, mid);
// 递归划分右半区域
msort(arr, tempArr, mid + 1, right);
// 合并已经排序的位置
merge(arr, tempArr, left, mid, right);
}
}
// 合并
private static void merge(int[] arr, int[] tempArr, int left, int mid, int right) {
// 标记左半区域的一个未排序的元素
int l_pos = left;
// 标记右半区域的一个未排序的元素
int r_pos = mid + 1;
// 临时数组元素的下标
int pos = left;
// 合并
while (l_pos <= mid && r_pos <= right){
if (arr[l_pos] < arr[r_pos]){ // 左半区域第一个剩余元素更小
tempArr[pos++] = arr[l_pos++];
}else{ // 右半区域第一个剩余元素更小
tempArr[pos++] = arr[r_pos++];
}
}
// 以下时当其中一个组中的元素都被放完了,即没有比较了,另一个组的元素直接放进去就行
// 合并左半区剩余的元素
while(l_pos <= mid){
tempArr[pos++] = arr[l_pos++];
}
// 合并右半区域剩余的元素
while (r_pos <= right){
tempArr[pos++] = arr[r_pos++];
}
// 把临时数组中合并的元素赋值回原来的数组
while(left <= right){
arr[left] = tempArr[left];
left++;
}
}
}