文章目录
- 1.邮资问题
- 2. 定理K
- 3.逆序对
1.邮资问题
此前曾经讲到希尔排序在对矩阵逐列排序时所使用的算法本身未必需要十分高效,而更重要的是应该具有输入敏感的特性,因此我们更倾向于使用插入排序。那么背后的具体原因又当如何解释呢?这里的核心依然是逆序队。
让我们从所谓的邮资问题开始,假设在某个国家寄送一封平信需要5毛钱,而寄送一张明信片只需3毛5。进一步的,我们假设在这个国家所发行的邮票只有面值为4分以及1毛3的两种。那如果你需要邮寄一封平信或者明信片,你是否能够恰好用这两类邮票凑出所对应的邮资呢?稍作思考之后,我想你不难找出平信所对应的邮资方案。
是的,正如这幅图所画的那样,我们只需6张面额为4分的邮票,外加两张面额为一毛三的邮票,就恰好可以凑出平信所对应的邮资,也就是5毛钱。然而对于明信片,我想你会和我一样,无论如何苦思冥想也不能找出一种恰好的邮资方案。
如果你感兴趣,甚至可以编写几行简单的代码来穷举所有的可能,你将会发现:在这个国家的确无法贴出明信片所对应的邮资3毛5。由此我们可以看到,使用特定的一组邮票,对于有些邮资,我们可以恰好的凑出,而有些邮资无论如何都不能恰好的凑出,那么为什么会有这样的区别呢?
对于其他的邮资而言,我们又有什么样的一般性规律呢?翻译成数学的语言,我们可以说在这个国家用4分和1毛3面额的邮票所能凑出的邮资必然是4m 加上13n 的形式。这样一个有整数相乘,然后累加而形成的表达式,也称作线性组合 Linear combination。
当然我们也可以将以上的邮资问题推而广之,比如分别用 g 和 h 来代表两种邮票的面额,而用 m 和 n 分别代表这两类邮票所使用的数量。于是由 m 枚面额为 g 的邮票以及 n 枚面额为 h 邮票所共同构成的邮资,就可以表示为这样一个形式,也就是更一般意义上的 linear combination。
不难理解,通过线性组合我们的确可以凑出不同的邮资。但是正如我们已经看到的,有些邮资却总是无法凑出。实际上我们更加关注于后一类的邮资,对于面额特定的两枚邮票,我们不妨将所有不能由他们凑出的邮资汇成一个集合并记作 N(g,h)。
我们最为关注的是这个集合中的最大者,我们将其记作 X(g,h)。那么对于任何一对互素的 g 和 h,X 又是多少呢?
在此我们直接引述数论中的现成结论,数论告诉我们,X(g,h) 应该等于(g-1)*(h-1) - 1。当然你可以化简为很多别的形式,比如说 gh - g - h。
我不妨就刚才的实例来做一验证,也就是说在 g = 4,h = 13时,按照这个定理,x 应该等于4和13的乘积,再减去4和13的总和。不出意外,恰好就是35,也就是刚才明信片所对应的邮资。
当然,这个定理也告诉我们,从3毛6开始向上,所有的面额都是可以由这两种邮票凑出的。只要这两种邮票足够多。这样一个邮资的问题虽然有趣,但是它与我们这里的希尔排序又有什么关系呢?
2. 定理K
回到排序问题,我们首先来引入 h-sorting 以及 h-ordered 这两个概念。在某个序列中,如果任何一对距离为 h 的元素,都保持前小后大的次序,我们就称它为 h-ordered,也就是以 h 为间隔,是有序的。
当然作为其中的一个特例,在任何一个 one-ordered 的序列中,根据定义任何一对相邻的元素,彼此之间都是顺序的。应该记得我们在最初介绍起泡排序算法时就指出,某个序列中只要任何相邻的元素之间都是彼此顺序的,那么必然就是整体有序。所以我们说任何 one-ordered的序列,也必然是全局有序的。也就是我们排序算法最初需要输出的结果。
那么对于任何一个随机序列,如何使它变成是 h-ordered 的呢?
实际上如这幅图所示,我们只需采用希尔排序的那种方法,将输入的一维序列在逻辑上转换为一个宽度为 h 的矩阵,然后分别的逐列排序。你应该记得将整个序列在逻辑上转化为一个宽度为 h 的矩阵,并且逐列进行排序。在希尔排序中就称为 h-sorting。
由此我们可以做一简洁的归纳,也就是任何一个序列在做过 h-sorting 之后,必然是 h-ordered。
你应该记得在希尔排序中,每向前迭代一步,对应的矩阵宽度都会相应地减少。比如从前一轮的 g 减少为后一轮的 h。我们知道在经过前一轮的逐列排序之后,整个序列应该是 g-ordered。而在后一轮的逐列排序之后,这个序列也自然的应该是 h-ordered。那么在整个序列也达到以 h 为间隔有序的同时,此前以 g 为间隔的有序性是否能够依然得以延续呢?
这个问题的答案并不是那么一目了然。所幸的是 Knuth 已经在他那本著名的专注中给出了正面的答案。Knuth 指出:任何一个原先已是g-ordered 的序列在此后经过h-sorting 之后,依然保持是g-ordered。 也就是说相对于任何一个固定间隔而言的有序性,在希尔排序的过程中将会不断地保持并且持续地积累下来。
3.逆序对
现在还是回到我们的线性组合,考察我们的待排序列,如果它既是 g-ordered,同时也是 h-ordered。这样的序列也称作是 gh-ordered。实际上这样的序列也必然会以 g 和 h 之和为步长,是有序的。
我可以通过这个图来简明地证明这一点。在整个序列中考察任何一对相距 g + h 的元素,我们说它们必然是顺序的。因为我们可以找到,居于它们中间的这样一个特定的元素,这个元素到前一元素的距离为 g,而到后一元素的距离为 h。于是以这个中间元素为桥梁,根据不等式的单向传递性,我们自然就可以得知,这一对间隔为 g + h 的元素也必然是顺序的。
实际上这个结论也可以进一步地推广到 g 和 h 的任何一个线性组合。
我们仍然通过这组图来加以说明。在这序列中,我们考察任何一对间距为这个线性组合的元素。为了证明这一对元素之间的顺序性,我们无非是将刚才的方法推而广之,也就是说我们需要引入更多的中间桥梁。
比如这里给出的就是一种具体的方案,我们首先以 g 为间隔,连续地取出 m 个元素,在这些间隔位置上的所有元素必然是单调非降的。接下来我们再以 h 为间隔,连续地取出 n 个元素。同样的,这 n 个元素也必然是单调非降。于是通过所有这些单调不等号的串接,我们也就自然地证明了这样一对元素之间的顺序性。
由以上我们可以概括出一个结论:也就是凡是间距可以表示为线性组合的任何一对元素,必然是顺序的。简而言之,凡能表示为线性组合,则必然顺序。
现在我们将注意力集中于序列中秩为 i 的那个元素,如果 g 和 h 是互素的,而且整个序列已经是同时关于 g 和 h 有序的,那么相对于这个元素,哪些元素必然是顺序的?反过来哪些元素才有可能是逆序的?
我们说实际上可能逆序的元素不会很多,确切地讲无非就是刚才关于 g 和 h 的那个 x,也就是不能由 g 和 h 线性组合生成的最大的那个整数。
你能看出其中的原因吗?没错,对于这个区间之后的任何一个元素而言,它与 i 的距离已经超出了这个最大的阈值 x,所以它们之间的间隔也必然可以表示为 g 和 h 的线性组合。
而我们刚刚总结过,凡是能够表示为线性组合的,也就是顺序。反过来,i 这个元素所能参与构成的逆序对,只可能出现于这样一个范围(灰色区)。而随着希尔排序的不断迭代,这个范围也会不断地缩小。
没错,逆序列的总数会不断持续的减少。由此,你能想到点什么吗?没错,插入排序。我们知道插入排序具有输入敏感性,它的实际运行时间将线性正比于序列中所含逆序对的总数。
至此,我们终于弄明白了,为什么在希尔排序的底层,我们更加倾向于使用插入排序算法。实际上按照以上的优化思路,后人针对希尔排序曾经设计过许多更为优化的步长序列,比如 PS 序列、Pratt 以及 sedgewick 序列。