目录
归并排序的介绍
归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。
归并排序的时间,空间复杂度:
归并排序是一个效率比较快的算法,所以我们有必要了解一下该算法的实现思想(如果能自己写出代码是更好的)。
归并排序实现思想
归并排序的过程由分和治两个过程构成。
分: 简单来说,就是把一个待排序的数组,分成一个又一个的子数组,将他们排成有序的数组;
治: 将这些排序完成的子数组,合并在一起,完成排序。
上一张图大家可能会有更好的理解:
归并排序代码讲解
为了更好更容易的理解该算法,我先摆上代码,通过理解代码更清晰的掌握该算法思想。
public class MergeSort {
public static void main(String[] args) {
int[] arr = new int[]{8,4,5,7,1,3,6,2};
int[] temp = new int[arr.length];
mergeSort(arr,0,arr.length - 1,temp); // left:0 right:7
System.out.println("归并排序后:" + Arrays.toString(arr));
}
//分+合的方法
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);
}
}
/**
*合并的过程
* @param arr 待排序的数组
* @param left 左边有序序列的初始索引
* @param mid 中间索引
* @param right 右边有序序列的初始索引
*/
public static void merge(int[] arr , int left , int mid ,int right , int temp[]){
int i = left; // 初始化i , 表示左边有序序列的初始索引
int j = mid + 1; //初始化j ,右边有序序列的初始索引
int t = 0; //指向temp数组(辅助数组)的当前索引
//(1)
//先把左右俩边的数据按照规则填充到temp数组
//直到两边的有序序列,有一边处理完毕为止
while(i <= mid && j <= right){
//如果左边的有序序列的当前元素,小于等于右边有序序列的当前元素
//就将左边的当前元素,拷贝到temp数组
if(arr[i] <= arr[j]){
temp[t] = arr[i];
t++;
i++;
}else{
//反之就将右边的当前元素,拷贝到temp数组
temp[t] = arr[j];
t++;
j++;
}
}
//(2)
//把有剩余数据的一边的数据全部填充到temp中
while (i <= mid){//左边的有序序列还有剩余元素
temp[t] = arr[i];
t++;
i++;
}
while (j <= right){//右边的有序序列还有剩余元素
temp[t] = arr[j];
t++;
j++;
}
//(3)
//将temp数组的元素拷贝到arr
//这里的代码其实就是一个数组的拷贝过程
t = 0;
int tempLeft = left; //templeft是辅助指针,left就是temp[]的首索引
System.out.println("tempLeft=" + tempLeft + " right=" + right);
while(tempLeft <= right){
arr[tempLeft] = temp[t];
t++;
tempLeft++;
}
}
}
我们先来看治的这个过程:
- 在这个过程中,我们需要一个temp[]辅助数组来帮助我们完成这个过程。
- 该方法需要的参数有,待排序的数组,数组的初始索引,数组的末位置索引,数组的中间索引,已经temp[]辅助数组
待排序的数组是: 8 5 4 7 1 3 6 2;
分之后的两部分别为:4 5 7 8 ; 1 2 3 6
- 分别定义两个指针(图中的i和j),指向两个子数组的首索引(4和1);
- 通过比较两个的大小,小的一方,放入到temp数组中,然后指针向后移动;直到一个子数组遍历结束为止;
- 然后将未遍历完的子数组的数据也放入到temp数组中去;
- 最后将temp[]辅助数组的内容全部拷贝到原数组中去;
理解难点:
我个人认为在这个算法的代码中,治的代码倒是很好理解,主要是分+治的这个过程用到了递归,如果对递归掌握的不太清楚的话,可能还真有点迷糊,所以我就尽我可能的分享给大家我所理解的。
整个递归的过程还是蛮复杂的,这一篇可能是写给自己的理解的,如果你看不懂也没关系,确实逻辑有点乱,过段时间我可能重新写一次,那时候可能会更加让读者易懂~~
执行结果:
文中的一些图片是借用别人的。