归并排序
定义
归并排序(merge sort)是高效的基于比较的稳定排序算法。
性质
归并排序基于分治思想将数组分段排序后合并,时间复杂度在最优、最坏与平均情况下均为
归并排序可以只使用
过程
合并
归并排序最核心的部分是合并(merge)过程:将两个有序的数组 a[i]
和 b[j]
合并为一个有序数组 c[k]
。
从左往右枚举 a[i]
和 b[j]
,找出最小的值并放入数组 c[k]
;重复上述过程直到 a[i]
和 b[j]
有一个为空时,将另一个数组剩下的元素放入 c[k]
。
为保证排序的稳定性,前段首元素小于或等于后段首元素时(a[i] <= b[j]
)而非小于时(a[i] < b[j]
)就要作为最小值放入 c[k]
。
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
也可使用 <algorithm>
库的 merge
函数,用法与上述指针式写法的相同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
分治法实现归并排序
当数组长度为
时,该数组就已经是有序的,不用再分解。当数组长度大于
时,该数组很可能不是有序的。此时将该数组分为两段,再分别检查两个数组是否有序(用第 1 条)。如果有序,则将它们合并为一个有序数组;否则对不有序的数组重复第 2 条,再合并。
用数学归纳法可以证明该流程可以将一个数组转变为有序数组。
为保证排序的复杂度,通常将数组分为尽量等长的两段(
实现
注意下面的代码所表示的区间分别是
1 2 3 4 5 6 7 8 9 10 11 |
|
1 2 3 4 5 6 7 8 9 |
|
倍增法实现归并排序
已知当数组长度为
将数组全部切成长度为
从左往右依次合并两个长度为
从左往右依次合并两个长度
从左往右依次合并两个长度
……
重复上述过程直至数组只剩一个有序段,该段就是排好序的原数组。
为什么是 而不是
数组的长度很可能不是
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
1 2 3 4 5 6 7 8 9 |
|
逆序对
逆序对是
排序后的数组无逆序对,归并排序的合并操作中,每次后段首元素被作为当前最小值取出时,前段剩余元素个数之和即是合并操作减少的逆序对数量;故归并排序计算逆序对数量的额外时间复杂度为 merge
过程的 if(b[j] < a[i])
部分加上 cnt += aLen - i
或 cnt += aEnd - aBegin
即可,对于 Python 代码将 merge
过程的 if(b[j] < a[i]):
部分加上 cnt += len(a) - i
即可。
此外,逆序对计数即是将元素依次加入数组时统计当前大于其的元素数量,将数组离散化后即是区间求和问题,使用树状数组或线段树解决的时间复杂度为
外部链接
本页面最近更新:2023/10/4 21:50:08,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面贡献者:NachtgeistW, ChungZH, Enter-tainer, Great-designer, H-J-Granger, iamtwz, invalid-email-address, Ir1d, IronSublimate, Junyan721113, ksyx, lychees, mcendu, Menci, minghu6, ouuan, partychicken, Saisyc, Shawlleyw, sshwy, Tiphereth-A, untitledunrevised, weisi, Xeonacid, zexpp5
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用