【详解排序算法】归并排序

大家好🙌我是你们的好朋友,大数据老虾😀。相遇是缘,既然来了就拎着小板凳坐下来一起唠会儿😎,如果在文中有所收获,请别忘了一键三连,动动你发财的小手👍,你的鼓励,是我创作的动力😁!废话不多说,直接😎 开干吧!

PS:文末干货,记得拎着小板凳离开的时候也给它顺走 🤣
座右铭:“懒”对一个人的毁灭性有多大,早起的重要性就多大


归并排序

算法分析

解析:
归并排序体现了“分而治之”的算法思想,具体表现为:

  • 分: 指不断将数组从中心位置划分,将原数组的排序问题转换为子数组的排序问题。
  • 治: 划分到子数组长度为1时,开始向上合并,不断将左右两个较段排序数组合并为一个较长排序数组,直至合并至原数组时完成排序。

如下图所示:

为数组[7, 3, 2, 6, 0, 1, 5, 4]的归并排序过程:

在这里插入图片描述

算法流程

递归划分:

1、计算数组中点m,递归1划分左子数组merge_sort(1, m)和右子数组merge_sort(m + 1, r);

2、当 l ≥ r时, 代表子数组长度为1或0, 此时终止划分,开始合并;

合并子数组:

1、暂存数组,nums闭区间[l, r]内的元素至辅助数组tmp;

2、循环合并:设置双指针 i, j 分别指向tmp的左 / 右子数组的首元素;

注意:
    nums子数组的左边界、重点,右边界分别为 l 、m、r;
    辅助数组tmp中对于的索引为0、m - l、r - l;
  • 当 i = m - l + 1时: 代表左子数组已合并完,因此添加右子数组元素tmp[j],并执行 j = j + 1;

  • 否则,当 j = r - l + 1时: 代表右子数组已合并完,因此添加左子数组元素 tmp[i] ,并执行 i = i + 1;

  • 否则,当 tmp[i] ≤ tmp[j] 时: 添加左子数组元素 tmp[i] ,并执行 i = i + 1;

  • 否则(即当 tmp[i] > tmp[j] 时): 添加右子数组元素 tmp[j] ,并执行 j = j + 1;

//  java code
void mergeSort(int[] nums, int l, int r) {
    // 终止条件
    if (l >= r) return;
    // 递归划分
    int m = (l + r) / 2;
    mergeSort(nums, l, m);
    mergeSort(nums, m + 1, r);
    // 合并子数组
    int[] tmp = new int[r - l + 1]; // 暂存需合并区间元素
    for (int k = l; k <= r; k++)
        tmp[k - l] = nums[k];
    int i = 0, j = m - l + 1;       // 两指针分别指向左/右子数组的首个元素
    for (int k = l; k <= r; k++) {  // 遍历合并左/右子数组
        if (i == m - l + 1)
            nums[k] = tmp[j++];
        else if (j == r - l + 1 || tmp[i] <= tmp[j])
            nums[k] = tmp[i++];
        else {
            nums[k] = tmp[j++];
        }
    }
}

// 调用
int[] nums = { 3, 4, 1, 5, 2, 1 };
mergeSort(nums, 0, len(nums) - 1);
# python code
def merge_sort(nums, l, r):
    # 终止条件
    if l >= r: return
    # 递归划分数组
    m = (l + r) // 2
    merge_sort(nums, l, m)
    merge_sort(nums, m + 1, r)
    # 合并子数组
    tmp = nums[l:r + 1]       # 暂存需合并区间元素
    i, j = 0, m - l + 1       # 两指针分别指向左/右子数组的首个元素
    for k in range(l, r + 1): # 遍历合并左/右子数组
        if i == m - l + 1:
            nums[k] = tmp[j]
            j += 1
        elif j == r - l + 1 or tmp[i] <= tmp[j]:
            nums[k] = tmp[i]
            i += 1
        else:
            nums[k] = tmp[j]
            j += 1

# 调用
nums = [3, 4, 1, 5, 2, 1]
merge_sort(0, len(nums) - 1)

如下动图所示,为数组 [7,3,2,6] 的归并排序过程 :
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

算法特性

  • 时间复杂度: 最佳 Ω(NlogN) ,平均 Θ(NlogN) ,最差 O(NlogN) 。
  • 空间复杂度 O(N) : 合并过程中需要借助辅助数组 tmp ,使用 O(N) 大小的额外空间;划分的递归深度为 logN ,使用 O(logN) 大小的栈帧空间。

若输入数据是 链表 ,则归并排序的空间复杂度可被优化至 O(1) ,这是因为:

1、通过应用「双指针法」,可在 O(1) 空间下完成两个排序链表的合并,省去辅助数组 tmp 使用的额外空间;
2、通过使用「迭代」代替「递归划分」,可省去递归使用的栈帧空间;

  • 非原地: 辅助数组 tmp 需要使用额外空间。
  • 稳定: 归并排序不改变相等元素的相对顺序。
  • 非自适应: 对于任意输入数据,归并排序的时间复杂度皆相同。

文末彩蛋🤩

🚗🤩😉💖🌹👀✨给各位朋友安利一下平时收集的各种学习资料!!!有需要的朋友点击一下传送门,自行领取。程序员经典名言:“收藏了就等于学会啦”。 做人也要像蜡烛一样,在有限的一生中有一分热发一份光,给人以光明,给人以温暖!
图灵程序丛书300+
Linux实战100讲
Linux书籍
计算机基础硬核总结
计算机基础相关书籍
操作系统硬核总结
Java自学宝典
Java学习资料
Java硬核资料
Java面试必备
Java面试深度剖析
阿里巴巴Java开发手册
MySQL入门资料
MySQL进阶资料
深入浅出的SQL
Go语言书籍
我的个人仓库:私人仓库

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值