Perl 排序与查找最小值/最大值的线性搜索

Perl 排序与查找最小值/最大值的线性搜索,perl,sorting,complexity-theory,Perl,Sorting,Complexity Theory,最近,我在perl中遇到了下面一段代码,它返回所有传递参数中的最小数值 return 0 + ( sort { $a <=> $b } grep { $_ == $_ } @_ )[0]; 返回0+(排序{$a$b}grep{$\==$\}@[0]; 我通常使用简单的线性搜索来查找列表中的最小值/最大值,这对我来说似乎是简单且充分优化的。上面的代码在任何方面都比简单的线性搜索好吗?在这种情况下,与perl有关吗?谢谢 你说得对。如果您不需要出于任何其他目的对数据进行排序,那么简单

最近,我在perl中遇到了下面一段代码,它返回所有传递参数中的最小数值

return 0 + ( sort { $a <=> $b } grep { $_ == $_ } @_ )[0];
返回0+(排序{$a$b}grep{$\==$\}@[0];

我通常使用简单的线性搜索来查找列表中的最小值/最大值,这对我来说似乎是简单且充分优化的。上面的代码在任何方面都比简单的线性搜索好吗?在这种情况下,与perl有关吗?谢谢

你说得对。如果您不需要出于任何其他目的对数据进行排序,那么简单的线性搜索是最快的。无论如何,排序要完成它的工作,必须至少查看每个数据一次

只有当排序后的数据对其他用途有用时——或者当我不关心运行时、功耗、散热等时——我才会对数据进行排序以找到最小值和最大值

现在,@simeonviser是正确的。排序没有O(n*log(n))这并不像许多程序员想象的那样慢于O(n)。在感兴趣的实际案例中,管理排序的平衡二叉树(或其他类似结构)的开销可能与日志(n)因子一样重要。因此,人们不必害怕分类的前景!但是,线性搜索速度更快:这一点您是完全正确的

此外,@DavidO还添加了一条很有见地的评论,我在这里用他自己的话说:


线性搜索也是一种更容易推广的算法。例如,对于大型数据集,线性搜索可以很容易(并且相对有效)基于磁盘。然而,执行基于磁盘的排序会变得相对昂贵,如果字段大小不一致,则会变得更加复杂 正常化

线性搜索是O(n),原因很明显。排序是O(n logn)(参见Perl文档中的)。因此,是的,线性搜索在复杂性方面确实更快。这不仅适用于Perl,而且适用于实现这些算法的任何编程语言

与许多问题一样,有多种方法可以解决它,也有多种方法可以获得列表的最小/最大值。从概念上讲,如果只需要列表的最小值或最大值,那么线性搜索会更好,因为问题不需要排序。

O()没有说明算法需要多长时间。例如,在所有其他条件相同的情况下,我总是在以下两种算法中选择算法2:

  • 算法1:O(2*N+1000天)=O(N)
  • 算法2:O(5*N+100ms)=O(N logn)
O()指定算法随着输入大小的增加而缩放的时间。(好吧,它可以用于任何资源,而不仅仅是时间。)因为前面两个答案只涉及O(),所以它们是无用的

如果您想知道一个算法的速度,对于给定大小的输入,哪种算法更好,您需要对它们进行基准测试

在这种情况下,看起来s
min
总是非常好

$ perl x.pl 10
           Rate  sort LUmin
sort  1438165/s    --  -72%
LUmin 5210584/s  262%    --

$ perl x.pl 100
           Rate  sort LUmin
sort   129073/s    --  -91%
LUmin 1485473/s 1051%    --

$ perl x.pl 1000
          Rate  sort LUmin
sort    6382/s    --  -97%
LUmin 199698/s 3029%    --
代码:

使用严格;
使用警告;
使用基准qw(CMP准则);
使用列表::Util qw(最小值);
我的%tests=(
'sort'=>'my$x=(sort{$a$b}@n)[0];',
“LUmin”=>“我的$x=min@n;”,
);
$\='使用严格的;使用警告;我们的@n;'$_
对于%测试值;
本地我们@n=map rand,1..($ARGV[0]//10);
cmpthese(-3,\%测试);

线性搜索也是一种更容易推广的算法。例如,对于大型数据集,线性搜索可以很容易(并且相对有效)基于磁盘。然而,进行基于磁盘的排序会变得相对昂贵,如果字段大小没有标准化,则会变得更加复杂。在其他条件相同的情况下,当N=1000时,O(N logn)比O(N)慢10倍。这不是一点。当然,正如我在回答中所解释的,真正的答案可能是O()与OP的问题完全无关。@ikegami:你是对的。然而,众所周知,程序员被O()符号所误导,这正是我试图表达的观点。代数上,log(n)的阶数为零——正好为零,就像常数1的代数阶数为零一样。为什么?因为L'Hospital的规则;或者,如果你愿意,因为log(n)/n^epsilon收敛于正epsilon,而发散于负epsilon,即使epsilon很小。值得考虑的是O(sqrt(n))比O(log(n))差多少。实际上,O(log(n))比许多程序员认为的更像O(1)。就复杂性而言,s/确实更快/确实随着输入的大小增加而扩展得更好。O(N)没有告诉你任何关于速度的事情。例如,一个O(N)算法可能需要1200天来处理100个元素(2*N+1000天)。哇,这是一个全面的解释!List::Util::min使用什么技术来计算最小值?@Sanjay,这是一个用C编写的线性搜索。
use strict;
use warnings;

use Benchmark  qw( cmpthese );
use List::Util qw( min );

my %tests = (
   'sort'  => 'my $x = ( sort { $a <=> $b } @n )[0];',
   'LUmin' => 'my $x = min @n;',
);

$_ = 'use strict; use warnings; our @n; ' . $_
   for values %tests;

local our @n = map rand, 1..( $ARGV[0] // 10 );
cmpthese(-3, \%tests);