【问题标题】:What is the fastest sort algorithm for 0-65535 integers?0-65535 整数最快的排序算法是什么?
【发布时间】:2010-09-22 01:12:13
【问题描述】:

我必须对一些整数进行排序,它们的值可以在 30.000.000 到 350.000.000 之间。将有 0 到 65.535 个整数,平均数为 20.000。 RAM 的使用无关紧要,速度很重要。

稍后我还必须将它们分成组,只要其中两个值之间的差距大于 65.535,就会始终设置除法,这就是我需要算法的目的。

如果有任何不同,算法将在 Perl 脚本中使用。

编辑:仔细考虑并阅读答案后,我意识到:我实际上并不关心数据本身。由于我真的只想找到有小差距的组的开始和结束值,所以排序只需要创建桶并且可以丢弃数据。

Edit2:经过一些测试并尝试了所提供的答案,我发现最快的方法是:

my @sort = sort {$a <=> $b} @item_offsets;
my @buckets;
my $start = shift @sort;
push @buckets, [$start,$start];
for my $item ( @sort ) {
    if ( $item < $buckets[$#buckets][1]+$gap ) {
        $buckets[$#buckets][1] = $item;
    }
    else {
        push @buckets, [$item,$item];
    }
}
say $#buckets;

【问题讨论】:

    标签: perl algorithm sorting performance


    【解决方案1】:

    我会在运行算法之前创建一个桶数组,每组 65536 个连续值一个。存储桶将包含其内容的最小值和最大值,但不会存储内容本身。运行算法后,对桶进行一次遍历。如果有两个连续的非空桶 min(bucket2)-max(bucket1)

    注意Bucket Sort

    【讨论】:

    • 你很好地总结了这些问题。实际上,在阅读此处的回复时,我曾考虑过做类似的事情,但还不太确定。谢谢。 :)
    • 我刚刚根据您的编辑编辑了我的答案并删除了一些不相关的文本。虽然两者都是线性时间算法,但最终的答案应该更快。
    【解决方案2】:

    我会试试这个:

    my @sorted = map { unpack "N" } sort map { pack "N" } @unsorted;
    

    【讨论】:

    • 恐怕地图对我来说有点黑魔法。那段代码有什么作用? oO
    • 我假设 map{} 是为了消除对 sortsub 进行数字比较的需要。 {$a $b} 案例自 5.6.1 以来已进行了优化,因此不再需要这种诡计了。
    • 您必须从右到左阅读此内容。 map { pack "N" } @unsorted 将 pack "N" 应用于每个元素——将每个元素转换为大端二进制数——输出被传递给具有 O(n log n) 行为的排序,并且每个排序结果的元素被解包并分配给@sorted。
    • @michael:不知道。很有趣。
    【解决方案3】:

    您不太可能在 Perl 中编写比 Perl 的内置 sort 函数执行得更好的排序算法:

    @numbers = sort {$a <=> $b} @numbers;
    

    您可以尝试使用 sort pragma 来查看特定算法是否更好:

    use sort '_quicksort';
    use sort '_mergesort';
    

    由于您的切点会因数据分布而异,我认为您需要先对整个列表进行排序,然后循环遍历它以进行切割。

    my $prev  = shift @numbers;  # already sorted
    my @group = [$prev];
    my $i     = 0;
    
    foreach my $n (@numbers) {
        $i++ if ($n - $prev > 65535);
        push @{$group[$i]}, $n;
        $prev = $n;
    }
    

    【讨论】:

    • 感谢您提醒我 Perl 排序功能。我都忘记了。
    【解决方案4】:

    如果您使用该数字作为数组的索引,然后增加该位置的计数,则您已将它们“分组”,并一次性完成。

    在伪代码中:

    while(morenumbers)
      sorted[[unsorted[number]]++
      number++
    

    如果提前知道范围,您可以减少索引值(例如,将 value-30000 带入正确的范围)。

    【讨论】:

    • 坏主意,因为范围远大于整数的数量(5000 万 vs 65000),所以这个“一次通过”会很慢。
    • 你不能超过一次通过,因为在任何现有的排序算法中,你必须至少命中未排序列表中的每个元素一次。 Perl 代码看起来更像我的@sorted_values; foreach 我的 $element (@unsorted_values) { $sorted_values[$element]++; };
    • 啊!我插入了换行符以避免让 Perl 代码看起来像单行代码那样糟糕!
    • 我一开始尝试做这样的事情,但是,我真的负担不起 300MB 的 RAM 使用,因为这会使它变得小得无法接受。但是我意识到我可以制作许多这样的桶,从而保持 ram 的使用合理。
    • > 如何初始化数组?该数组由 Perl 自动初始化。最初的问题询问如何对数组进行排序,而不是如何输出它。最初的问题还说“RAM 的使用无关紧要,速度很重要”,但显然 RAM 也有限制。
    【解决方案5】:

    我只是想说基数排序,http://en.wikipedia.org/wiki/Radix_sort 但是这可能比你想要实现的要高一点,Introsort 通常是公认的数据排序解决方案http://en.wikipedia.org/wiki/Introsort,它是快速排序的一种变体,可以切换到当它到达较小的集合时进行堆排序,因为它在较小的集合上比快速排序更快。

    【讨论】:

      【解决方案6】:

      我会使用基数排序,因为您需要对输出进行分组。

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-04
      • 1970-01-01
      • 2011-01-17
      • 2011-11-27
      • 1970-01-01
      • 2013-06-23
      相关资源
      最近更新 更多