shell排序的最快差距序列?

时间:2010-03-29 16:23:16

标签: algorithm performance sorting shellsort

根据Marcin Ciura的Optimal (best known) sequence of increments for shell sort algorithm, 炮弹的最佳顺序是1,4,10,23,57,132,301,701 ......, 但是我怎么能产生这样的序列呢? 在Marcin Ciura的论文中,他说:

  

Knuth和Hibbard的序列   是相对糟糕的,因为他们是   由简单的线性递归定义。

但是我发现的大多数算法书都倾向于使用Knuth的序列:k = 3k + 1,因为它很容易生成。你生成一个弹壳序列的方法是什么?

6 个答案:

答案 0 :(得分:14)

Ciura的论文以经验方式生成序列 - 也就是说,他尝试了一系列组合,这是最有效的组合。生成最佳的弹壳序列已被证明是棘手的,迄今为止该问题对分析具有抵抗力。

最着名的增量是Sedgewick,您可以阅读 here (参见第7页)。

答案 1 :(得分:5)

如果您的数据集的大小有明确的上限,那么您可以对步骤序列进行硬编码。如果您的数据集可能在没有上限的情况下增长,您应该只担心一般性。

所显示的序列似乎大致成长为一个指数序列,尽管有些怪癖。似乎有大多数素数,但在混合中也有非素数。我没有看到明显的一代公式。

一个有效的问题,假设您必须处理任意大的集合,是否需要强调最坏情况性能,平均情况性能或几乎排序的性能。如果是后者,您可能会发现使用二进制搜索进行插入步骤的普通插入排序可能比弹出窗口更好。如果你需要良好的最坏情况表现,那么Sedgewick的序列似乎更受青睐。您提到的序列针对平均情况性能进行了优化,其中比较次数超过了移动次数。

答案 2 :(得分:4)

我不会羞于接受维基百科Shellsort文章中给出的建议,

  

关于平均比较数,最着名的差距   序列是1,4,10,23,57,132,301,701和类似的,具有间隙   通过实验发现。超过701的最佳间隙仍然未知,但很好   结果可以通过扩展上述顺序来获得   递归公式h_k = \ lfloor 2.25 h_ {k-1} \ rfloor。

     

Tokuda的序列[1,4,9,20,46,103,...],由简单公式h_k = \ lceil h'_k定义   \ rceil,其中h'k = 2.25h'k - 1 + 1,h'1 = 1,可推荐用于   实际应用。

从化名猜测,似乎Marcin Ciura自己编辑了WP文章。

答案 3 :(得分:2)

序列为1,4,10,23,57,132,301,701,1750。对于1750之后的每个下一个数字,将前一个数字乘以2.25并向下舍入。

答案 4 :(得分:0)

我发现这个序列类似于Marcin Ciura的序列:

1, 4, 9, 23, 57, 138, 326, 749, 1695, 3785, 8359, 18298, 39744, etc.

例如,Ciura的序列是:

1, 4, 10, 23, 57, 132, 301, 701, 1750

这是素数的平均值。找到素数均值的Python代码在这里:

import numpy as np

def isprime(n):
    ''' Check if integer n is a prime '''
    n = abs(int(n))  # n is a positive integer
    if n < 2:  # 0 and 1 are not primes
        return False
    if n == 2:  # 2 is the only even prime number
        return True
    if not n & 1:  # all other even numbers are not primes
        return False
    # Range starts with 3 and only needs to go up the square root
    # of n for all odd numbers
    for x in range(3, int(n**0.5)+1, 2):
        if n % x == 0:
            return False
    return True

# To apply a function to a numpy array, one have to vectorize the function
vectorized_isprime = np.vectorize(isprime)

a = np.arange(10000000)
primes = a[vectorized_isprime(a)]
#print(primes)
for i in range(2,20):
    print(primes[0:2**i].mean())

输出结果为:

4.25
9.625
23.8125
57.84375
138.953125
326.1015625
749.04296875
1695.60742188
3785.09082031
8359.52587891
18298.4733887
39744.887085
85764.6216431
184011.130096
392925.738174
835387.635033
1769455.40302
3735498.24225

序列中的差距从2.5缓慢下降到2。 也许这种关联可以在未来改善Shellsort。

答案 5 :(得分:0)

我昨天讨论了这个问题here,包括我发现在给定特定(低)n时最好的间隙序列。

在中间我写

  

一个令人讨厌的副作用是当使用一组随机时   n个条目的组合(以节省处理/评估时间)进行测试   你可能最终得到n个条目的最佳差距或者   你的组合最佳差距 - 很可能是后者。

问题在于测试拟议的差距,以便得出有效的结论。显然,测试所有n的差距!一组n个唯一值可以表示为不可行的排序。例如,以这种方式对n = 16进行测试意味着必须对20,922,789,888,000个n值的不同组合进行排序以确定精确的平均,最差和反向排序的情况 - 只是为了测试一组间隙而该集合可能不是最好。对于n = 16,可以有2 ^(16-2)组间隙,第一组是{1},最后是{15,14,13,12,11,10,9,8,7,6,5,4 ,3,2,1}。

为了说明使用随机组合如何给出不正确的结果假设n = 3可以假设六个不同的顺序012,021,102,120,201和210.你产生一组两个随机序列来测试两个可能的间隙集,{1}和{2,1}。假设这些序列结果为021和201.对于{1} 021可以用三个比较(02,21和01)和201与(20,21,01)进行分类,总共进行六次比较,除以2和voilà,平均为3,最差情况为3.使用{2,1}给出(01,02,21和01)021和(21,10和12)为201.七个比较与最坏情况的4,平均3.5。 {1]的实际平均值和最差情况分别为8/3和3。对于{2,1},值为10/3和4.两种情况下的平均值都太高,最坏的情况是正确的。如果有一个案例{1}会给出2.5的平均值 - 太低了。

现在将其扩展为找到n = 16的一组随机序列,这样与其他序列相比,测试的间隙集不会受到青睐,并且结果与真值接近(或等于),同时保持处理至少。可以吗?有可能。毕竟,一切皆有可能 - 但可能吗?我认为对于这个问题,随机是错误的方法。根据某个系统选择序列可能不那么糟糕,甚至可能是好的。