归并排序方法就是把一组n个数的序列,折半分为两个序列,然后再将这两个序列再分,一直分下去,直到分为n个长度为1的序列。然后两两按大小归并。如此反复,直到最后形成包含n个数的一个数组。
合并有序序列
原有两个有序数组:
创建一个长度为两个序列长度和的数组,s1、s2游标在原序列进行遍历,按大小比较放入新数组中。
无序序列怎么变有序
先将一个无序序列拆分成小组,再进行有序序列合并。
归并排序流程:
-
不断拆分,直到所有数据变成一个一组为止
-
再进行合并,合并过程中借助一个临时空间进行排序
-
以此类推,最后数组就会变得有序
时间复杂度:
时间复杂度 = 轮数 * 每一轮里的时间复杂度 = O(nlogn)
第一轮:一个数组 2^0
第二轮:两个数组 2^1
第三轮:四个数组 2^2
........
第k轮:2 ^ (k-1) = n 即:k = log2n
每一轮里的时间复杂度:n
代码实现:
通过递归方法实现。
递归关系:
当需要向左拆分时,f(arr, left, i); 当需要向右拆分时,f(arr, i+1, right)
递归出口:
left = right
import java.util.Arrays;
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 i = (left + right)/2;
//向左拆分
mergeSort(arr, left, i);
//向右拆分
mergeSort(arr, i+1, right);
//调用合并的方法
merge(arr, left, i, right);
}
/*合并*/
public static void merge(int[] arr, int left, int middle, int right) {
//第一个序列
int s1 = left;
//第二个序列
int s2 = middle+1;
//定义临时数组
int[] temp = new int[right-left+1];
//定义游标遍历临时数组
int index = 0;
//比较大小,将小的数放入临时数组中
while(s1<=middle && s2<=right) {
//s1小
if(arr[s1]<=arr[s2]) {
temp[index] = arr[s1];
index++;
s1++;
}else {//s2小
temp[index] = arr[s2];
index++;
s2++;
}
}
//当右半组都放入临时数组后,将左半部分剩下的数依次放入
while(s1<=middle) {
temp[index] = arr[s1];
index++;
s1++;
}
//当左半组都放入临时数组后,将左半部分剩下的数依次放入
while(s2<=right) {
temp[index] = arr[s2];
index++;
s2++;
}
//把临时数组当中的数据返回原数组
for(int j=0; j<temp.length; j++) {
arr[j+left] = temp[j];
}
}
}
其中,把临时数组当中的数据返回原数组时,j+left 的原因: