归并排序
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治的思想。将已有序的子序列合并,得到完全有序的序列,既先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,成为二路归并
需求:
排序前:{8,4,5,7,1,3,6,2}
排序后:{1,2,3,4,5,6,7,8}
排序原理:
1、尽可能的一组数据拆分为两个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组的元素个数是1为止。
2、将相邻的两个子组进行合并成一个有序的大组
3、不断的重复步骤2,知道最终只有一个组为止。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JFIbtuyZ-1612087446661)(C:\Users\29455\AppData\Roaming\Typora\typora-user-images\1612007588557.png)]
代码实现:
//数组合并过程
public static void Sort(int[] a, int l, int m, int r, int[] temp){
int i = l;
int j = m + 1;
int t = 0;
//将原来的数组拆分并后比较大小并排序,保存在新的temp数组中
while(i <= m &&j <= r){
if(a[i] <= a[j]){
temp[t] = a[i];
i++;
t++;
}else{
temp[t] = a[j];
j++;
t++;
}
}
//把有剩余数据的一边的数据一次全部填充到temp
//左边剩余
while(i <= m){
temp[t] = a[i];
t++;
i++;
}
//右边剩余
while(j <= r){
temp[t] = a[j];
t++;
j++;
}
//三、将temp的数据拷贝到a中
t = 0;
int templeft = l;
while(templeft <= r){
a[templeft] = temp[t];
t++;
templeft++;
}
}
//分数组 + 数组合并
public static void MergeSort(int[] a ,int l, int r, int[] temp){
if(l < r){
int m = (l + r) / 2;
//向左进行递归分解
MergeSort(a, l, m, temp);
//向右进行递归分解
MergeSort(a, m + 1, r, temp);
//合并
Sort(a, l, m, r, temp);
}
}
public static void main(String[] args) {
int[] a = {8,4,5,7,1,3,6,2};
int[] temp = new int[a.length];
MergeSort(a, 0 , a.length - 1, temp);
System.out.println(Arrays.toString(a));
}
运行结果
[1, 2, 3, 4, 5, 6, 7, 8]
归并排序时间复杂度分析
总时间=分解时间+解决问题时间+合并时间。分解时间就是把一个待排序序列分解成两序列,时间为一常数,时间复杂度o(1).解决问题时间是两个递归式,把一个规模为n的问题分成两个规模分别为n/2的子问题,时间为2T(n/2).合并时间复杂度为o(n)。总时间T(n)=2T(n/2)+o(n).这个递归式可以用递归树来解,其解是o(nlogn).此外在最坏、最佳、平均情况下归并排序时间复杂度均为o(nlogn).从合并过程中可以看出合并排序稳定。
=2T(n/2)+o(n).这个递归式可以用递归树来解,其解是o(nlogn).此外在最坏、最佳、平均情况下归并排序时间复杂度均为o(nlogn).从合并过程中可以看出合并排序稳定。
用递归树的方法解递归式T(n)=2T(n/2)+o(n):假设解决最后的子问题用时为常数c,则对于n个待排序记录来说整个问题的规模为cn。 在拆分过程中,第一层时间为cn, 第二层时间代价为cn/2+cn/2=cn……每一层代价都是cn,总共有logn+1层。所以总的时间代价为cn*(logn+1).时间复杂度是o(nlogn).