归并排序的学习
思想
由大到小
归并算法是分治算法的典型问题
1.需要我们将一个数组拆成许多的有序子序列(相当于只有一个元素)
2.然后将这些有序子序列进行两两排序组合成新的子序列,然后将这些子序列进行进一步排列组合(组合的时候需要创建一个和数组长度相同的备用数组)
3.组合时的思路就是:两个子序列的第一个数相比较,把小的放到第一位,然后拿另一个数B与其他数作比较如果这个数B比另一个数大,那么把另一个数放进去,如果这个数B比另一个数小,那么把B放进去,拿另一个数当作B再做比较,当一个子序列的数全部放进去后,直接把剩余的都放到后面。
4.最后将合并的序列从创建的数组复制到原数组中
图示
下面的图表示归并排序的过程
上半部分表示分的阶段l,m,r分别表示序列的左下标,中间下标和右下标。
下半部分表示和的阶段,tempLeft和tempRight表示要合并的两部分的起始下标。
代码部分
代码主要分为合并算法以及递归算法(分与和的实现)
ps:如果递归的过程不是很了解的话可以参考递归算法的一些理解
ps:通过对arr[]数组在不同位置的遍历分析可以知道分与和是同时进行的
public class Merge {
public static void main(String[] args) {
int[] arr = {5, 2, 9, 7, 6, 4, 8, 3};
int[] temp = new int[arr.length];
mergeSort(arr,0,arr.length-1,temp);
System.out.println(Arrays.toString(arr));
}
/**
* 由大到小
* 归并算法是分治算法的典型问题
* 需要我们将一个数组拆成许多的有序子序列(相当于只有一个元素)
* 然后将这些有序子序列进行两两排序组合成新的子序列,然后将这些子序列进行进一步排列组合
* 组合时的思路就是 两个子序列的第一数相比较,把大的放到第一位,然后拿另一个数与其他数作比较
* 如果大于这个数那么放进去,如果小于这个数那么把这个数放进去,拿下一个数再做比较
* 当一个子序列的数全部放进去后,直接把剩余的都放到后面
*/
//合并算法
public static void merge(int[] arr, int left, int mid, int right, int[] temp) {
int tempLeft = left;//左边那一部分的起始下标
int tempRight = mid + 1;//右边那一部分的起始下标
int t = 0;//temp数组的起始下标
//1.将两部分各取一个进行比较大小,然后将小的数放入temp,直到有一边取完
while (tempLeft <= mid && tempRight <= right) {
if (arr[tempLeft] <= arr[tempRight]) {
temp[t] = arr[tempLeft];
tempLeft++;
t++;
} else {
temp[t] = arr[tempRight];
tempRight++;
t++;
}
}
//2.当有一边取取完后,将另一边剩余的数放入temp中
while (tempLeft <= mid) {
temp[t] = arr[tempLeft];
tempLeft++;
t++;
}
while (tempRight <= right) {
temp[t] = arr[tempRight];
tempRight++;
t++;
}
//3.将合并好的序列从temp数组复制到arr数组
int l = left;
t = 0;
while (l <= right) {
arr[l] = temp[t];
t++;
l++;
}
}
//递归算法
//分和合
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);//合并
}
}
}
ps:在递归算法中加上
foreachArray(temp);
foreachArray(arr);
printLine();
可以对每一次递归后的temp数组和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);//合并
foreachArray(temp);
foreachArray(arr);
printLine();
}
}
foreachArray
public static void foreachArray(int[] arr){
System.out.println(Arrays.toString(arr));
}
printLine
public static void printLine(){
System.out.println("----------华丽的分割线-----------");
}
运行结果
[2, 5, 0, 0, 0, 0, 0, 0]
[2, 5, 9, 7, 6, 4, 8, 3]
----------华丽的分割线-----------
[7, 9, 0, 0, 0, 0, 0, 0]
[2, 5, 7, 9, 6, 4, 8, 3]
----------华丽的分割线-----------
[2, 5, 7, 9, 0, 0, 0, 0]
[2, 5, 7, 9, 6, 4, 8, 3]
----------华丽的分割线-----------
[4, 6, 7, 9, 0, 0, 0, 0]
[2, 5, 7, 9, 4, 6, 8, 3]
----------华丽的分割线-----------
[3, 8, 7, 9, 0, 0, 0, 0]
[2, 5, 7, 9, 4, 6, 3, 8]
----------华丽的分割线-----------
[3, 4, 6, 8, 0, 0, 0, 0]
[2, 5, 7, 9, 3, 4, 6, 8]
----------华丽的分割线-----------
[2, 3, 4, 5, 6, 7, 8, 9]
[2, 3, 4, 5, 6, 7, 8, 9]
----------华丽的分割线-----------
[2, 3, 4, 5, 6, 7, 8, 9]
从中可以看出分和合是同时进行的
小结
本人也是刚开始接触排序算法,通过别人的博客,视频,以及自己的理解对归并算法进行了一些总结。归并算法对于递归的一些运用也是理解的不够深入。