归并排序的算法原理:该算法采用经典的分治策略,分是指将问题分成许多小的问题,然后递归求解,而治则是将分的阶段得到的各答案"修补"在起,即分而治之。
归并排序图解:图片如有侵权请联系本人
合并相邻子序列:
归并排序代码框架:
public class MergeSort {
/**
* 分治算法:分阶段,将数组每个元素分开
* @param arr 待排序数组
* @param left 待排序数组最左边索引
* @param mid 待排序数组中间索引
* @param right 待排序数组最右边索引
* @param temp 临时数组
*/
public static void Merge(int[]arr,int left,int mid,int right,int[]temp){
...
}
public static void MergeSort(int[] arr,int left,int right,int[]temp){
...
}
public static void main(String[] args) {
调用MergeSort
}
}
直接讲解代码:
待排序的数组:arr = {8,4,5,7,1,3,6,2} | 临时数组:temp = { } | |
归并排序的两个函数 | MergeSort(arr,left,right,temp) | Merge(arr,left,mid,right,temp) |
第一次:(进入主函数) | ||
left = 0 | right = arr.length-1 = 7 | mid = (left+right)/2 = 3 |
递归退出条件: left<right,即0<7 | 开始执行左递归函数 | |
第二次:(进入左递归1)左递归函数:MergeSort( arr , left , mid , temp ),right = mid | ||
left = 0 | right = mid = 3 | mid = (left+right)/2 = 1 |
递归退出条件:left<right,即0<3 | 左递归:MergeSort(arr,0,3,temp) | |
第三次:(进入左递归2) | ||
left = 0 | right = mid = 1 | mid = (left+right)/2 = 0 |
递归退出条件:left<right,即0<1 | 左递归:MergeSort(arr,0,1,temp) | |
第四次:(退出左递归,执行下一条函数语句) | ||
left = 0 | right = mid = 0 | mid = (left+right)/2 = 0 |
递归退出条件:left<right,即0<0不成立 | 开始执行右递归 | |
第五次:(进入右递归1)右递归函数:MergeSort( arr, mid+1 , right , temp ),left = mid+1 | ||
mid = (left+right)/2 = 3 , 第1次中的left和right | left = mid+1 = 4 | right = arr.length-1 = 7 |
递归退出条件:left<right,即4<7 | 右递归:MergeSort(arr,4,7,temp) | |
第六次:(进入右递归2) | ||
mid = (left+right)/2 = 5 | left = mid+1 = 6 | right = arr.length-1 = 7 |
递归退出条件:left<right,即6<7 | 右递归:MergeSort(arr,6,7,temp) | |
第七次(退出右递归,执行下一条函数语句) | ||
mid = (left+right)/2 = 6 | left = mid+1 = 7 | right = arr.length-1 = 7 |
递归退出条件:left<right,即7<7不成立 | 退出右递归 | |
第八次(开始执行Merge操作)Merge(arr,left,mid,right,temp) |
Java栈内存演示:函数执行出栈操作,从上往下执行;
第一阶段:左递归阶段
第二阶段:右递归阶段
第三阶段:Merge阶段
import java.util.Arrays;
public class MergeSort {
/**
* 分治算法:分阶段,将数组每个元素分开
* @param arr 待排序数组
* @param left 待排序数组最左边索引
* @param mid 待排序数组中间索引
* @param right 待排序数组最右边索引
* @param temp 临时数组
*/
public static void Merge(int[]arr,int left,int mid,int right,int[]temp){
// 0.初始化操作
int i=left; // 左边有序序列索引
int j=mid+1; // 右边有序序列索引
int t=0; // 临时数组的当前索引
// 1.先把左右两个数组按照有序规则填充到temp数组,直到两边的有序序列有一边处理完为止
while (i<=mid&&j<=right){
// 处理左边
if (arr[i]<=arr[j]){
temp[t]=arr[i];
t++;
i++;
}else {// 处理右边
temp[t]=arr[j];
j++;
t++;
}
}
// 2.把有剩余的数据一边依次全部填充到temp
// 2.1左边数据有剩余
while (i<=mid){
temp[t]=arr[i];
t++;
i++;
}
// 2.2右边数据有剩余
while (j<=right){
temp[t]=arr[j];
t++;
j++;
}
// 3.将temp数组的元素拷贝到arr,注意不是每次拷贝所有的arr数组元素
t = 0; //让t指向temp首元素
int tempLeft = left;
while (tempLeft<=right){
arr[tempLeft] = temp[t];
t++;
tempLeft++;
}
}
public static void MergeSort(int[] arr,int left,int right,int[]temp){
if (left<right){
int mid = (left+right)/2;
// 向左递归
MergeSort(arr,left,mid,temp);
// 向右递归
MergeSort(arr,mid+1,right,temp);
// 递归结束之后
Merge(arr,left,mid,right,temp);
}
}
public static void main(String[] args) {
int[] arr = {8,4,5,7,1,3,6,2};
int[] temp = new int[arr.length];
int left = 0;
int right = arr.length-1;
int mid = (left+right)/2;
System.out.println("原数组:"+Arrays.toString(arr));
MergeSort(arr,left,right,temp);
System.out.println("归并排序:"+Arrays.toString(arr));
}
}
运行结果: