思路
归并排序是一种经典的排序算法,采用分治法的思想。它将待排序的数组分成两个较小的子数组,分别对这两个子数组进行排序,然后将排好序的子数组合并成一个有序的数组。
归并排序的主要思路如下:
-
分解:将待排序的数组递归地分解成较小的子数组,直到每个子数组只有一个元素为止。这可以通过不断地将数组分成两半来实现。
-
解决:对每个子数组进行排序。当子数组只有一个元素时,它已经是有序的。
-
合并:将排好序的子数组合并成一个大的有序数组。这是通过比较两个子数组的最前面的元素,并将较小的元素放入新的数组中,然后将相应子数组的指针向后移动来实现的。重复这个过程,直到所有的元素都被放入新数组中。
-
递归:重复以上步骤,直到最终整个数组排序完成。
总结一下,归并排序的核心思想是分治和合并。通过递归地将数组分解成较小的子数组,然后对这些子数组进行排序,并最终合并成一个有序的数组。
拆分过程
if(left>=right){
return;
}
int mid = (left+right)/2;
mergeSort(arr,left,mid);
mergeSort(arr,mid+1,right);
排序合并
当我们拆分完成之后,其中5和7我们可以认为是有序的,之后我们要将进行合并操作,将两个有序的小数组合并成一个大的有序数组,首先定义一个和当前要合并的数组大小一样的临时数组。
int[] temp = new int[right-left+1];
之后我们定义两个游标,对两个有序数组内的元素进行比较进行排序并合并到临时数组中,
int s1 = left;
int s2 = mid + 1;
if(arr[s1]<=arr[s2]){
temp[i++] = arr[s1++];
}else {
temp[i++]=arr[s2++];
}
现在我们就可以认为5和7一定是有序的了
添加到临时数组之后需要把数据写回原数组
for(int j = 0;j<temp.length;j++) {
arr[j+left] = temp[j];
}
接下来的步骤就是递归重复合并的代码了!!!!
上源码
首先强调:注意while循环的条件,画一下图,就能很简单的看出来!
看下图,s2指向空了,7能不能放进去呢?答案显而易见7是不会放进去的,如果没有后面条件就会造成bug。
public class MergeSort {
public static void main(String[] args) {
int[] arr = new int[] {5,7,4,2,0,3,1,6};
mergeSort(arr,0,arr.length - 1);
System.out.println(Arrays.toString(arr));
}
public static void mergeSort(int[] arr,int left,int right) {
//递归出口
if(left>=right) {
return;
}
int mid = (left +right)/2;
//拆分
mergeSort(arr,left,mid,mid);
mergeSort(arr,mid +1,right,mid);
//合并
//定义一个临时数组
int[] temp = new int[right - left +1];
int s1 = left;
int s2 = mid + 1;
int i =0;
while(s1<=mid && s2<=right) {
if(arr[s1]<=arr[s2]) {
temp[i++] = arr[s1++];
}else {
temp[i++] = arr[s2++];
}
}
while(s1<= mid) {
temp[i++] = arr[s1++];
}
while(s2<=right) {
temp[i++] = arr[s2++];
}
//将temp中的数据返回
for(int j = 0;j<temp.length;j++) {
arr[j+left] = temp[j];
}
}
}