实施睡眠排序


74

睡眠排序是我在Internet上找到的整数排序算法。它将打开一个输出流,并为每个并行输入的数字延迟数秒,然后输出该数字。由于延迟,最后输出的数字最大。我估计它具有O(n + m),其中n是元素数,m是最高数。

这是Bash中的原始代码

#!/bin/bash
function f() {
    sleep "$1"
    echo "$1"
}
while [ -n "$1" ]
do
    f "$1" &
    shift
done
wait

这是伪代码

sleepsort(xs)
 output = []
 fork
   for parallel x in xs:
     sleep for x seconds
     append x to output
 wait until length(output) == length(xs)
 return output

您的任务是使用您选择的编程语言将Sleep Sort实现为一个函数。您可以忽略任何竞争因素,例如竞争条件,并且永远不要锁定任何共享资源。最短的代码获胜。函数定义计入代码长度。

输入列表仅限于非负整数,并且输入列表的长度预计会相当长(测试至少10个数字),因此竞争条件永远不会发生。并假设种族条件永远不会发生。


3
长度算什么?完整的程序,包括IO还是相关的例程?
康拉德·鲁道夫

8
这个有问题。根据列表的顺序,在打印第一个值之前,您可能不会阅读整个列表。例如,一个大型列表需要45秒才能读取,第一个值为2,最后一个值为1。要打印的线程1可能在打印2之后执行。糟糕-输出不再正确排序。可能有一些解决方法-创建线程,然后在读取整个列表后启动线程(但这将导致更长的代码,不利于高尔夫)。我想知道是否有人可以解决这个潜在问题……我将尝试。
Thomas Owens

11
顺便说一句,使该算法真正有趣的是,实际上存在现实生活中的应用程序。例如,DNA测序(Sanger测序)取决于类似的事情,以便根据DNA片段的长度对其进行分类(更普遍的是,每次电泳都执行类似的操作)。不同之处在于排序是物理执行的,而不是在计算机中执行的。
康拉德·鲁道夫

12
我不想成为每个人都参加的游行,但是这不只是以O(N ^ 2)的方式将复杂性转移到OS调度程序上吗?
Random832

1
我认为有些物理排序算法需要O(n)时间,但需要O(n)个物理对象。好吧,我们可以用融化的蜡烛和一支试管来做到这一点。zh.wikipedia.org/wiki/Spaghetti_sort
Ming-Tang

Answers:


17

一种of脚的Perl尝试,59 55 52 38 32个字符

map{fork||exit print sleep$_}@a

准系统:25个字符:

...如果您不介意排序结果作为模具输出:

map{fork||die sleep$_}@a

所有的装饰物:

(为了获得最大的挑战合规性,为44个字符)

sub t{map{fork||exit print sleep$_}@_;wait}

如果让perl等待您,则39个字符:

sub t{map{fork||exit print sleep$_}@_}

再说一次,如果您不介意die(),请输入32个字符...

sub t{map{fork||die sleep$_}@_}

请注意,在Perl 6中或声明了“ say”功能时,可以用替换该print函数,并say在每个实例中保存一个字符。显然,由于die两者都终止了分叉的过程并写入了输出,因此它仍然是最短的解决方案。


你可以STIL运行perl-E,使5.010功能,如say
MBX

(fork&&die sleep$_)for@a也可以工作
malkaroee '16

20

C,127个字符,一个很明显的解决方案:

main(int c,char**v){
#pragma omp parallel for num_threads(c)
for(int i=1;i<c;++i){int x=atoi(v[i]);sleep(x);printf("%d ",x);}}

(已编译gcc -std=c99 -fopenmp sort.c并忽略了所有警告。)


4
太酷了,我真的必须学习运气
Nils

我会称其为93个字符(没有命令行解析等),但是令人印象深刻的是,在C语言中,您只能用34个额外的字符来做到这一点!
Rex Kerr

1
@KonradRudolph-您可以保存6个向后的字节:for(;c>=0;--c){int x=atoi(v[c]);。不知道是否允许。
owacoder

15

Ruby 1.9,32个字符

作为功​​能:

s=->a{a.map{|i|fork{p sleep i}}}

如果我们只能使用预定义的变量,则它将减少为25个字符:

a.map{|i|fork{p sleep i}}

1
您可以通过使用Thread.new{p sleep i}打印输出来节省很多字符。
霍华德

@霍华德:好收获,谢谢!
Ventero'6

@Ventero,我只是在学习Ruby,我想知道您将如何运行此lambda函数,或更具体地说是如何输入。是否可以与IRB一起运行?谢谢!
本·希利

14

JavaScript,65个字符(取决于您使用的console.log还是输出结果的其他方式)

a.map(function(v){setTimeout(function(){console.log(v)},v*1000)})

假设这a是一个非负整数数组,并且map()存在于数组原型(JavaScript 1.6+)上。


1
您可以通过乘以10(或9)而不是1000来删除两个或什至三个字符,而不会影响正确性。
Konrad Rudolph

12
如果打算保留一秒钟,则可以1e3改用。
乔伊(Joey)

2
@Tomalak alert是JavaScript的阻止输出,prompt是JavaScript的阻止输入,confirm也是JavaScript的阻止二进制输入。如果要在命令行上编写JS,则将使用这些调用。
zzzzBov 2011年

1
@zzzzBov,使用阻塞输出对于此任务几乎肯定是个坏主意。
彼得·泰勒

2
@zzzzBov,这是我担心的它们被调用的顺序-除非JS spec强烈保证setTimeout排队的重击的调用顺序。
彼得·泰勒

13

杀伤人员地雷(15 13)

{⎕←⍵⊣⎕DL⍵}&¨⎕

它能做什么:

¨⎕       : for each element of the input
&        : do on a separate thread
⎕DL⍵    : wait approx. ⍵ seconds
⎕←⍵     : output ⍵

我看到的是方框,而不是3个字符。
2012年

8
@ArtemIce:应该有三个盒子(四)。I / O变量是两个(读取该变量获取输入,写入该变量将打印输出),另一个是该⎕DL函数的名称,即sleep。
marinus 2012年

9

在Erlang中的四次尝试:

输出到控制台的操作很随意,9ms * Number因为这足以使它工作(在Atom嵌入式板上测试=慢):

需要60个字符

s(L)->[spawn(fun()->timer:sleep(9*X),io:write(X)end)||X<-L].

到控制台的输出完全是非英语的,因此我们发送一条消息来处理P

需要55个字符

s(P,L)->[spawn(fun()->timer:sleep(9*X),P!X end)||X<-L].

一段时间后的发送方式也可以不同(甚至适用于1ms * Number):

需要41个字符

s(P,L)->[erlang:send_after(X,P,X)||X<-L].

实际上,这有点不公平,因为如果我们认为此命名空间已导入(在模块级别完成),则内置函数send_after是一个较晚的应用,并且需要erlang:前缀该命名空间:

需要34个字符

s(P,L)->[send_after(X,P,X)||X<-L].

7

C#-137个字符

这是C#的答案(已更新为并行度,如注释所示)

void ss(int[]xs){xs.AsParallel().WithDegreeOfParallelism(xs.Length).Select(x=>{Thread.Sleep(x);return x;}).ForAll(Console.WriteLine);}

1
您需要指定WithDegreeOfParallelism它的工作方式,类似于num_threads我的OpenMP C代码中的。
Konrad Rudolph

120个字节:void m(int[] l){foreach(var i in l){var t=new Thread(()=>{Thread.Sleep(int.Parse(s));Console.Write(s);});t.Start();}}}
MrPaulch '17

@MrPaulch请注意,如果您希望程序具有预期的行为,则需要再次加入线程
另一个极客

为什么?最长的运行线程将使进程保持活动状态。
MrPaulch

7

的Python-81 93 148 150 153

调整@BiggAl的代码,因为那是我们正在玩的游戏...

import threading as t,sys
for a in sys.argv[1:]:t.Timer(int(a),print,[a]).start()

...或97 175 线程启动延迟

import threading as t,sys
for x in [t.Timer(int(a),print,[a]) for a in sys.argv[1:]]:x.start()

通过命令行输入数据,ala

./sleep-sort\ v0.py 1 7 5 2 21 15 4 3 8

与许多python高尔夫球一样,有一点代码的紧凑性很强,以至于别名别名缩短名称甚至都不会保存字符。

尽管这很时髦,因为它将sys别名和线程均别名为t,因此sys.argv变为t.argv。比从foo import *短,并且节省了净字符!但是我想Guido不会很高兴...

自我注意-学习c并停止在python中打高尔夫球。 天哪,这比C解决方案还差!


我设法进行了一些调整,但是格式在注释中显示不佳,所以我做出了自己的回答。daemon除非您将其作为守护程序启动,否则不需要设置,并且使用位置args,esp更短。如果您别名NoneN
theheadofabroom,2011年

哦,第一个在2.7.1下对我不起作用,j似乎最终变成False-尝试在一行中做太多的副作用?
theheadofabroom 2011年

该死,我没有意识到您可以将多个模块导入同一个别名-实际上,我想到了一些用途,其中我有多个相同子类的自定义基类位于不同的子模块中。如果我们能再刮掉30个,那它比bash还短...但是我认为那不会发生。
theheadofabroom 2011年

啊,我之所以不知道,是因为你不能-我只是尝试运行它,并且线程没有别名,它被称为线程。这是sys的别名。您尝试运行此吗?尽管每个仅导入了两个字符as t,s,然后再更改为s用于sys
theheadofabroom 2011年

1
为什么不使用该print函数代替sys.stdout.write
飞羊

6

为了好玩,这里有一个ColdFusion(8+)版本;-)它有109个字符,不包括为便于阅读而添加的换行和缩进。

<cfloop array="#a#" index="v">
  <cfthread><cfthread action="sleep" duration="#v*1000#"/>#v#</cfthread>
</cfloop>

假设这<cfoutput>是有效的。通过将全部内容写在一行上可以节省一些字符。


6

爪哇(又名从未赢在codegolf):234 211 187个字符

public class M{public static void main(String[]s){for(final String a:s)new Thread(){public void run(){try{sleep(Long.parseLong(a));}catch(Exception e){}System.out.println(a);}}.start();}}

松散

public class M {
    public static void main(String[] s) {
        for(final String a:s) new Thread(){
            public void run() {
                try {
                    sleep(Long.parseLong(a));
                } catch(Exception e){}
                System.out.println(a);
            }
        }.start();
    }
}

@Joey感谢您设置正确。
真实性2011年

该课程可以是非公开的,节省7个字符。
Daniel Lubarov 2013年

1
您还可以声明throws Throwable并摆脱该catch条款。
Daniel Lubarov

我想你可以通过更换节省2个字节Long.parseLongLong.valueOf
HyperNeutrino '16

我知道已经有6.5年了,但是您可以打高尔夫球的某些部分:public并且final可以将其删除;class M{public static void main可以是interface M{static void main(Java 8+); Long.parseLong(a)可以new Long(a)(结果为165个字节
Kevin Cruijssen

5

Javascript-52个字符

for(i in a)setTimeout("console.log("+a[i]+")",a[i])

欢迎来到CodeGolf.SE!我已经为您格式化了答案,尤其是将代码缩进四个空格以使其显示为代码。您将在编辑页面的侧栏中找到其他格式帮助。
dmckee 2011年

5

Scala- 42 40个字符(特殊情况)

如果您有一个线程池,其大小至少等于列表元素的数量:

a.par.map{i=>Thread.sleep(i);println(i)}

Scala-72个字符(常规)

a.map(i=>new Thread{override def run{Thread.sleep(i);println(i)}}.start)

{}一条线上不使用的afaik 。
飞羊

@flying Sheep-您可以省略{}一个语句,但是仍然需要用它来将用;,或不分隔一行的内容分组。而且您可以编写多行语句,而{}在某些情况下(例如,如果使用if / else)。
Rex Kerr

哦,我并不是说您可以省略它们,而是可以将其()用作单衬纸。我认为这是一个口味问题。(我只是真的不明白为什么(){}取代它们时根本不支持它们。也许不是立即疏远java用户)。Scala很酷,但是通过缩进定义代码块显然更好。(因此,发生了宗教战争;))
飞羊

@飞羊-您误会了。您可以使用()单个语句。尝试输入(1 to 9).map(i => {val j = i+1; i*j})REPL,然后查看如果使用会发生什么(1 to 9).map(i => (val j = i+1; i*j))
Rex Kerr

是的,但我仅提及表达和内容。抱歉,我讨厌写东西而不能使用换行符;)
飞羊

4

Haskell-143个字符

import Control.Concurrent
import System
d=threadDelay
f x=d(10^6*x)>>print x
g s=mapM(forkIO.f)s>>d(10^6*maximum s+1)
main=getArgs>>=g.map read

如果可以的话,可以通过在stdin上输入来缩短输入时间,但这很晚了,无论哪种方式,函数本身仍然是104个字符。


4

Befunge-98,38 31个字节

我知道这是一个古老的挑战,但是我最近才发现sleepsort和2D语言,对如何将它们组合起来有了一个想法,并寻找一个发布它的地方,所以我们到了。

&#vt6j@p12<'
v:^ >$.@
>:!#^_1-

主IP读取一个数字(&),然后点击将t其克隆的一个:一个在同一行上并循环,读取新数字并生成新子代,直到到达终止该序列的EOF。所有子进程都陷入一个闭环中(第三列的v^),直到主IP完成输入的读取并执行命令序列'<21p,这会将字符<置于位置(1,2),覆盖^并释放所有字符子进程开始同时循环,每次迭代将其数量减少1。由于不同IP的执行速度是同步的,因此它们将按顺序终止(并打印其值),并对输入列表进行排序。


通过将控制流移动约26个字节
乔·金

3

晚会晚了一点:

枫木-91 83个字符

在91:

M:=():use Threads in p:=proc(n)Sleep(n);:-M:=M,n;end:Wait(map(i->Create(p(i)),L)[])end:[M];

在83中:

M:=():use Threads in Wait(seq(Create(proc(n)Sleep(n);:-M:=M,n end(i)),i=L))end:[M];

(这需要Maple版本15,并希望列表以L排序)


3

C,70 69个字符

不要等待子进程返回,否则可以工作。

main(n) {
    while(~scanf("%d",&n)?fork()||!printf("%d\n",n,sleep(n)):0);
}

2

PHP 57字节

<?for(;$i=fgets(STDIN);)pcntl_fork()?:die($i.usleep($i));

pcntl_fork()仅在Linux下可用。


2

重击(38):

xargs -P0 -n1 sh -c 'sleep $0;echo $0'

编辑:从stdin浮点数,由空格或换行符分隔。


2

90岁的哈斯克尔

import Control.Concurrent
s::[Int]->IO()
s=mapM_(\x->forkIO$threadDelay(x*9999)>>print x)

我希望这可以满足所有要求。



1

只是对@rmckenzie的版本进行了一些调整:

Python延迟线程启动 155 152 114 108 107:

import sys, threading as t
for x in [t.Timer(int(a),sys.stdout.write,[a]) for a in sys.argv[1:]]:x.start()

毫无延迟的Python 130 128 96 95 93:

import sys,threading as t
for a in sys.argv[1:]:t.Timer(int(a),sys.stdout.write,[a]).start()

使用Timer代替进行了更多优化,Thread这使调用更加简洁,并消除了import的需要time。延迟线程启动方法得益于列表理解功能,因为它不需要在开始时单独初始化列表,尽管它"["+"]"+" "-":"比for循环长两个字符(),所以在没有延迟启动的情况下它是无用的,并且您必须小心使用列表而不是生成器,或者直到您对生成器进行分块之后才真正创建计时器线程。

其他人还有什么优化吗?


这个技巧as很有帮助,但是在2.7.1中,您只能将一个模块导入别名,并且经过一番import mod1,mod2 as a,b尝试后甚至不能这样做import mod1 as a, mod2 as b。它仍然可以保存一些字符,但是还不能完全治愈,我以为是...实际上,最好将sys保留为sys。别名线程仍然有帮助...


你让我被打败了 我喜欢x = []; x + = []。不知道你能做到这一点....
arrdem

...如果您松开循环中的[statement]和f(x)之间的空格,则可以在128中执行此操作...以某种方式我将其提高到127,但是我认为那是通过不计算最后的换行符(在CG中是合法的)。以为我会给您更新而不是成为工具并窃取您的代码。
arrdem 2011年

@rmckenzie去吧,我偷了你的。我一直对看到CG python很感兴趣-考虑到语言的目标,我觉得我做的很
不对劲

是的,老实说,大多数python高尔夫球场如何保持可读性……以字符的“玻璃地板”为代价,我真的感到震惊。看看这个:导入线程,sys为t
arrdem 2011年

1

Clojure,54岁

(defn s[n](doseq[i n](future(Thread/sleep i)(prn i))))


您可以通过内联省略defn(它的括号+参数列表:从54到43 chrs)来消除一些字符,或者使用fn代替defn=> len- = 2,所以我要在clj中说出它的43:D
test30

1

锈-150字节

这就是为什么您不使用Rust编写高尔夫球的原因,它比Java更冗长;)。依靠外部箱子crossbeam,没有它,情况会更糟。

|x|{extern crate crossbeam;crossbeam::scope(|s|for&v in x{s.spawn(move||{std::thread::sleep(std::time::Duration::from_secs(v));println!("{}",v)});})}

完整的测试程序:

fn main() {
    let z =
    |x|{extern crate crossbeam;crossbeam::scope(|s|for&v in x{s.spawn(move||{std::thread::sleep(std::time::Duration::from_secs(v));println!("{}",v)});})}
    ;
    z(&[4, 2, 3, 5, 7, 8, 9, 1, 6, 10])
}

0

有点无聊,C#的端口,只是再次开始使用该语言:

F#-90个字符

PSeq.withDegreeOfParallelism a.Length a|>PSeq.iter(fun x->Thread.Sleep(x);printfn "%A" x)

0

JavaScript的74

function(a){for(i=0;i<a.length;i++)setTimeout('alert('+a[i]+')',a[i]*1e3)}

或不符合标准的71/65个字符:

function(a){a.map(function(v){setTimeout('console.log('+v+')',v*1e3)})}

即使在2011年,我也认为function(a){a.map(function(v){setTimeout(console.log,v,v)})}至少可以在60个字节的浏览器中工作。当然这些天你会写a=>a.map(v=>setTimeout(console.log,v,v))
尼尔


0

VB.NET 100字节

因为VB.Net要求单行lambda只包含一个语句,所以此代码必须具有多行:

Array.ForEach(i, Async Sub(x)
Await Threading.Tasks.Task.Delay(x*1000)
Console.WriteLine(x)
End Sub)

取消高尔夫:

Option Strict Off

Sub Main(i() as String)
    Array.ForEach(i, Async Sub(x)
                         Await Threading.Tasks.Task.Delay(x * 1000)
                         Console.WriteLine(x)
                     End Sub)
End Sub

但是我不确定您是否要在字节数中计算导入语句,因为如果您不对它们进行计数,那么我可以这样写:

VB.NET 71字节

a.ForEach(i, Async Sub(x)
Await t.Delay(x*1000)
c.WriteLine(x)
End Sub)

取消高尔夫:

Option Strict Off
Imports t = System.Threading.Tasks.Task
Imports c = System.Console
Imports a = System.Array

Sub Main(i() as String)
    a.ForEach(i, Async Sub(x)
                     Await t.Delay(x * 1000)
                     c.WriteLine(x)
                 End Sub)
End Sub

0

Groovy,47个字节

假设在命令行上给出了数字...

args.each{i->Thread.start{sleep(i*22)print i}}


0

Mathematica,34或36个字节

RunScheduledTask[Print@#,{#,1}]&/@

只需将要排序的列表附加到此代码的末尾并进行评估。如果需要一个有效的函数定义,则它需要两个额外的字节:

RunScheduledTask[Print@#,{#,1}]&/@#&

0

C ++ 11,229个字节

#import<future>
#import<iostream>
using namespace std;int main(int a,char**v){auto G=new future<void>[a];while(--a){G[a]=move(async([=](){this_thread::sleep_for(chrono::seconds(atoi(v[a])));cout<<v[a]<<" "<<flush;}));}delete[]G;}

脱胶和用法:

#import<future>
#import<iostream>
using namespace std;
int main(int a,char**v){
 auto G=new future<void>[a];
 while(--a){
  G[a]=move(async(
   [=](){
    this_thread::sleep_for(chrono::seconds(atoi(v[a])));
    cout<<v[a]<<" "<<flush;
   }
  ));
 }
 delete[]G;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.