排序算法 Sleep Sort
排序算法好像是程序员学习编程最多的算法,也可能是算法研究者们最喜欢研究的算法了。排序有很多很多的算法,比如,冒泡,插入,选择,堆,快速,归并等等(你可以看看本站以前的那些文章:可视化的排序,排序算法比较,显示排序过程的python)这里向大家介绍一个“巨NB”的排序算法——Sleep Sort。
闲言少说,请看下面的代码(用Shell脚本写的)
#!/bin/bash function f() { sleep "$1" echo "$1" } while [ -n "$1" ] do f "$1" & shift done wait
用法如下:
./sleepsort.bash 5 3 6 3 6 3 1 4 7
相信你可以会去试一下这个脚本,也相你你试完后你一定会说——“我擦,真TMD排序了!”,我还是不要解释这段代码了,过多的解释会不如代码那么直接,而且解释会影响你对这个排序算法的NB性。只想说——这是正二八经的多线程、多进程排序啊。我们的Bogo排序也黯然失色啊。
下面我们需要对这个算法做一些分析——
1)让我们来分析一个这这个程序的算法复杂度,太简单了,不就是O(最大数的秒数),呵呵。所以,如果出现这样的数列将是恶梦的——2 1 4 3 2 1 99999999
2)这个排序好是好,但对于负数或浮点数就有bug了。负数的解决方案是,我们可以这样来:x/2+MaxInt/2(时间可能相当长,不过依然工作)。对于浮点数,看看下面的代码.
#!/bin/bash function f() { sleep $(echo "($2 - 1) + $1 / 10 ^ $2" | bc -l) echo "$1" } while [ -n "$1" ] do f "$1" $(echo -n "$1" | wc -c) & shift done wait
3)我们来看看各种语言版本的实现吧。
Java
public class SleepSort { public static void main(String[] args) { int[] ints = {1,4,7,3,8,9,2,6,5}; SortThread[] sortThreads = new SortThread[ints.length]; for (int i = 0; i < sortThreads.length; i++) { sortThreads[i] = new SortThread(ints[i]); } for (int i = 0; i < sortThreads.length; i++) { sortThreads[i].start(); } } } class SortThread extends Thread{ int ms = 0; public SortThread(int ms){ this.ms = ms; } public void run(){ try { sleep(ms*10+10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(ms); } }
Javascript
[javascript]function sleepsort() {
for (var i = 0, il = arguments.length; i < il; i++) {
(function(args, index) {
setTimeout(function() {
document.body.innerHTML += args[index] + ‘, ‘;
}, args[index]);
}(arguments, i));
}
};
[/javascript]
Brainfuck (关于这门语言,请参看这篇文章)
,>,>++++++++[<------<------>>-]
<<[>[>+>+<<-]>>[<<+,>,>++++++++[<------<------>>-]
<<[ ----------[++++++++++>----------]++++++++++
>[>+>+<<-]>>[<<+>>-]<<<-] >>>++++++[<++++++++>-]<.>.>>-]<<<-]
,----------[----------------------.,----------]
,---<<<+>>>-------[----------------------.,----------]
>> ----------[++++++++++>----------]++++++++++
>++++++[<++++++++>-]< ----------[++++++++++>----------]++++++++++
.>. ----------[++++++++++>----------]++++++++++
>++>+<<-]>>[<<+>>-]<<<-] >>[>[>+>+<<-]>>[<<----------[++++++++++>----------]++++++++++
>++,>,>++++++++[<------<------>>-]
<<
(全文完)
(转载本站文章请注明作者和出处 酷 壳 – CoolShell ,请勿用于任何商业用途)
《排序算法 Sleep Sort》的相关评论
呵呵,有意思~~~
我了个去,这也行,真是没想到啊,哈哈
外一数组中有一个数是“Integer.MAX_VALUE”,看看这算法要多久才能排完。哈哈。
it’s so crazy,very well!
其实这货就是基数排序的变种……
其实BF我倒是真没想到怎么做,学习一下
来一个python的版本:
import threading
def sleepsort(num):
print num,” “;
if __name__ == ‘__main__’:
for num in input(” input a python list of int:”):
(threading.Timer(num,sleepsort,(num,),{})).start();
太牛叉,以前没想到。。。
哈哈 有意思~~
也可以说是位排序(编程主机)上的一个变种
原来这样也能排序啊~~什么原理呢~~
@zhangna
啊?这还原理?这不就是比赛睡觉,看谁睡得长嘛。。。。
这排序法,夯的是时间啊,伤不起。
是啊,伤不起啊伤不起 :)
个人觉得真的很”NB”
如果数组里有一堆的相等的数值呢? 输出还可以, 但对结果数组操作的时候, 会…..?
在java下测试, 经常会出现这种情况:整体基本增序, 但是偶有, 几个跳梁的小丑让你乱一下. 先声明, 已经上锁, 如果不上锁的时候, 有可能出null, 甚至直接挂掉.
都把我电脑排死机了~~ 你NC的算法
时间可以设短点, 可以把排序的数做log, 这样复杂度可以减少到logN. 还可以先hash一遍到一个固定的范围里面,这样可以做到O(1). (hash能否做到还需要看具体的分布..)
fork and sleep $_, say last for @ARGV; 1 while 1 -wait
额。。给吞了。。 1 while 1 \ -wait
各种囧啊。。。真有创意
原来如此!
没有考虑代码执行的时间,要排序的数据达到一定的量后就会出错,特别是数据量大,又小数据在后面的情况!拓展拓展思路不错!
@lia0.0
不是说电子邮箱保密吗,头像都拿过来了,这是泄密啊! ㄒoㄒ
Brainfuck的跑不动啊:
Error: Unbalanced brackets.
an error occured
用的Ubuntu的bf包
实用性不高吧,如果值太大要sleep到什么时候?
貌似没有实用性阿…
哈哈,这个好玩,有创意
这个有点意思啊。扩展思路倒是不错
@future
可以做很多扩展的吧,从offset到压缩。
一个ruby的简写版:
ary =[5, 3 ,6 ,3 ,6 ,3 ,1 ,4 ,7]
ary.map {|e| Thread.new { sleep(e); p e } }.each { |thr| thr.join }
!博客每篇都是这样原创的?
相当于是用空间复杂度换时间复杂度嘛
java代码靠线程的睡眠时间等于是依靠线程的调度的顺序,而且这个代码所有的线程不是一起开始的。
算法应该不能保证绝对的正确性
33楼说得有理,在java下线程睡醒后能否马上运行要看调度者的意思啊。在数据大小比较相近的情况下会出现顺序错乱吧?!
哈哈,这个算法太有创意了,不过权当娱乐吧,真用起来恐怕有不少问题
1.如果某个数非常大,直接导致时间复杂度的飙升
2.如果要排序的数据量很多,因为一个数字对应一个线程,可能导致系统资源耗尽
@la.onger
哈哈,点出了真谛!
你以為他為什麼會照順序出來, 其實是 scheduler 排的呀!
所以這只是把排序 delegate 給 scheduler, 你們認為 scheduler 的時間空間複雜度是多少?
呵呵,这个在有很多数值一样,并且存在和这些一样的数相近的数时,排序的结果可能不准确吧
/*****************C++0x version******************************/
#include
#include
#include
#include
int main(int argc, char* argv[]) {
std::list v ;
for (int i(1) ; i void {
std::this_thread::sleep_for( std::chrono::duration(num) ) ;
std::cout << num << std::endl ;
}) ;
}
for ( auto & t : v ) { t.join() ; }
return 0;
}
@披麻皴
这个是稳定性问题。对于同键值的项目如果不能保持原排序状态,就是不稳定的。
linux新手,
function f() {
sleep “$1”
echo “$1”
}
我这里这样写会报错,把 function 去掉成功:
f() {
sleep “$1”
echo “$1”
}
http://loveexception.iteye.com/blog/679832
我写的比较算法也是多线程的
我擦,真TMD排序了!
我擦,真排序了!很受启发啊
这个排序不稳定,如果 输出的时间相对sleep较大 有时候不是完全有序
如果整数很多 不是要sleep很久??
这个时间复杂度的分析,我觉得有问题。“最大数的秒数”不是问题的规模。举例子说,O(n)中的n是问题的规模,而O(n)表示的是随着问题规模的变化,某算法对某计算资源,如时间,变化的趋势。这里,按我的理解分析一下。假设M为最大的整数。当只有一个元素被排序时,即n=1,平均所需时间为: sum(0:M)/M。当有两个元素排序时,每一种选择的排序时间为两者之间的大数。当一个数固定是,平均排序时间还是sum(0:M)/M。例如,(1,0),(1,1),…, (1,M)的排序时间分别为(0,1…,M)。这样的两个元素序列有M种,每种的平均排序时间都是sum(0:M)/M。那么,当n=2时,平均时间为sum(0:M)/M。依次类推,递归可得当n=M时,平均排序时间仍然是sum(0:M)/M。所以这个问题的O(n)应该是0,因为该算法的平均耗费时间是固定的,即sum(0:M)/M。另外,如果在单CPU上,M的值还要收进程数上限的制约。如果小数都在面可以多排些。大数在前面多的话,后面的可能就没有进程分了。当进程间切换时期超过一秒时,会不会出现问题呢?
还要注意的时,该算法在多CPU时完全没有scalability。
拙见,
马。
娱乐的而已。。干嘛去研究它的各种性能呢~
。。干嘛去很细节的研究这个性能呢。。博主也只是想传达一个信息“哇,这都行。真新奇”。。
@夜夜笙歌 呵呵。其实这似乎是个非比较排序的变种。