归并排序
1、归并排序原理
归并排序是采用了分治思想的一种排序算法。它是不断的将原数组分成大小相等的两个子数组(长度也可能相差1),最终当划分的子数组长度为1时,将这些只包含一个元素的子数组视为有序序列,然后将这些划分的有序的子数组合并成更大的有序数组。基本原理是将带排序序列分成多个子序列,分别进行递归排序,然后将已排好序的子序列归并在一起,得到完整的有序序列
2、实例分析
归并排序动态图
1) 假设有一个无序的列表如:[10, 17, 50, 7, 30, 24, 27, 45]
将数组进行平分,直到均分后的元素个数为1
2) 如上图所示,当分为单个时,此时进行排序,怎么排序那?因为10和17是一组,所以两者进行排序为10、17,然后50和7进行排序,排序结果为7、50,那30、24排序后变成24、30,最后的27、45排序后为24、45
3) 然后两组之间再进行排序,首先10和7对比,对比结果7小,那么将7放到一个空列表中,然后10和50进行对比,对比结果10小,将10追加到刚才的空列表中,排在7后面,然后17和50对比,对比结果17比较小,然后追加到空列表中,然后将50追加到空列表中,以此类推,那么排序结果如下图
继续按照第三步进行数组的合并,生成最终的排好序的数组
3、实例分析总图
对9、5、2、7、12、4、3、1、11进行归并排序总图
4、代码实现归并排序
// 分解数组
public void mergeDiv(int[] arrs, int left, int right) {
if (left < right) {
int[] temp = new int[arrs.length];
// 因为要均分,所以先找到中间位置
int mid = (left + right) / 2;
mergeDiv(arrs, left, mid);
mergeDiv(arrs, mid + 1, right);
// 分完之后,进行merge操作
merge(arrs, left, mid, right);
}
}
// 合并数组并排序
private void merge(int[] arrs, int left, int mid, int right) {
int[] temp = new int[right - left + 1]; // 创建临时数组
int i = left, j = mid + 1, k = 0;
while (i <= mid && j <= right) {
if(arrs[i]<arrs[j]){
temp[k++] = arrs[i++];
}else{
temp[k++] = arrs[j++];
}
}
// 当左子数组还有元素时,将剩余元素追加到临时数组之后即可
while(i<=mid){
temp[k++] = arrs[i++];
}
// 当右子数组还有元素时,将剩余元素追加到临时数组之后即可
while(j<=right){
temp[k++] = arrs[j++];
}
// 将临时数组的值覆盖回原数组
for(int m=0;m<temp.length;m++){
arrs[left+m] = temp[m];
}
}
5、时间复杂度分析
分解数组时每次将数组一分为二,直到分出元素个数为1为止,显然需要分割logn次;
合并的时候需要将左右两个子数组的元素全都遍历一次,进行n次的比较和添加操作,所以时间复杂度为O(nlogn)