深入理解 timsort 算法(1):自适应归并排序

750 查看

Python 的 timsort 算法出了名的晦涩难懂。这是情理之中的事,它非常复杂。不过,当你真正对它进行深入研究后,你会发现它“只不过”是归并排序的一个变种。这些变异,有的非常巧妙,有的则非常直接明了,总之令人印象颇为深刻。

我会通过一些例子,让你从基本的归并算法(mergesort)开始,逐步过渡到 timsort。在本文中,我将探讨如何实现基本的自适应归并排序算法(adaptive mergesort),该算法是 timsort 的核心。以后的文章会在此基础上,讨论timsort中更多具体的优化。

为了简单起见,我不打算考虑普遍情况,只考虑整型数组(很容易类推到其他类型, 也使得代码更容易理解)。需要说明的是,我将隐藏一些细节(可能会有一些不太严谨的地方)。所以,如果你希望了解算法的具体细节,还是应该参考Tim Peters的说明

对了,例子是 C 写的,Sorry。

那么,我们从最简单的归并算法开始吧。

假定你已经了解归并算法的原理(如果不知道的话,你就得问下度娘)。一起复习下:长度为1的数组是有序的;当数组长度n > 1,则将数组拆分为2部分(通常从数组中间拆分);分别对两部分进行归并排序;然后执行一次合并操作,遍历两个有序数组,依次将较小的元素插入结果数组,最终得到一个较大的有序数组。

上代码:

我没有贴出完整的代码,你可以在github中查看详情。

到了这一步,如果你是C程序员,可能有件让你非常心惊肉跳的事摆在你眼前:每次调用合并函数的时候,都频繁的申请、释放用于合并操作的内存(我们没检查null返回值,这可能也让你很纠结。除非在demo版中,我会在生产代码中检查返回值的,但愿这能让你宽心)。

我们只要稍稍修改一下原型,再封装一下就可以解决这个问题。