前几天看到一个博主翻译的一个算法,叫睡眠排序,原文链接:https://blog.csdn.net/zmazon/article/details/8514088

感觉这个算法十分有趣,在网上搜集了一些资料看一下都有什么脑洞大开的排序算法。

一:睡眠排序

原理:这个算法的核心思想就是对应多少个待排序的数字,就开多少个协程,让每个协程沉睡对应的数字时长(这里我让每个协程沉睡ms级别),沉睡之后打印对应数字,这样数字小的当然就先打印了,数字大的就后打印了,实现了排序功能。

代码如下:

package mainimport ("fmt""time"
)func main() {arr := []int{4, 3, 6, 8, 1, 5, 2, 9, 7, 34, 32, 53, 3}n := len(arr)ch := make(chan int, n) //用一个channel记录,防止主进程在有的协程还没有结束任务的时候就退出for i := 0; i < n; i++ {go func(t int) {time.Sleep(time.Millisecond * time.Duration(t)) //沉睡对应的arr[i]msfmt.Println(t)    //打印出来ch <- i //协程打印数字之后传一个变量到channel}(arr[i])}for i := 0; i < n; i++ {//等待所有的协程工作完毕<- ch}return
}

看到这里我想你当然也发现了这个算法的硬伤:1.如数字过大沉睡时间太久2.每个协程的启动时间不能视为同时,如果数字的距离很接近,但是下标相隔很远(会加大协程启动时间不一致的误差),会出现乱序。3.负数无法沉睡等问题。

所以这个算法就成为了一个欢乐的算法仅供大家娱乐。

这里的不过作为爱较真的河马小哥肯定不能仅仅就停留在这里,在这里我尝试解决一下这些问题,来尽可能让它变成一个更好玩的算法。

首先是负数的问题:可以考虑分开排序,把负数和正数分成两组来排序,正数正常排序,负数只要转为整数排序,然后再翻转就好了。

代码如下:

package mainimport ("fmt""sync""time"
)const Time = time.Millisecondfunc main() {arr := []int{4, 3, 6, 8, 1, 5, -9, 0, 2, 9, 7, 34, 32, 53, 3, -8, -38, -1}n := len(arr)arrNeg := []int{} //记录负数数组arrop := []int{}   //记录非负数数组mutex := sync.Mutex{}opint := 0  //统计非负数个数neint := 0    //统计负数个数//将arr数组中数字放入对应的数组中for i := 0; i < n; i++ {if arr[i] < 0 {arrNeg = append(arrNeg, arr[i])neint++} else {arrop = append(arrop, arr[i])opint++}}//记录负数的开始下标,由于沉睡负数 * -1ms 所以小数字会被后唤醒 所以负数下标从最后一个开始,非负数下标从第一个开始opindex := neintneindex := neint - 1ch := make(chan int, n) //用一个channel记录,防止主进程在有的协程还没有结束任务的时候就退出for i := 0; i < neint; i++ {go func (t int) {time.Sleep(Time * time.Duration(t * -1))ch <- i//用一个锁防止同时对neindex 和 arr数组进行更改mutex.Lock()defer mutex.Unlock()arr[neindex] = tneindex--}(arrNeg[i])}for i := 0; i < opint; i++ {go func (t int) {time.Sleep(Time * time.Duration(t))ch <- imutex.Lock()defer mutex.Unlock()arr[opindex] = topindex++}(arrop[i])}for i := 0; i < n; i++ {//等待所有的协程工作完毕<- ch}for i := 0; i < n; i++ {fmt.Print(" ", arr[i])}return
}

结果如下:

可以看到对于负数也可以正常排序了,这里我将沉睡的量级抽出来成为Time,发现如果Time小于ms级别是可能会出现相差较小数字之间出现错位的情况

然后其实是有的数字太小,出现乱序的问题,这个可以通过增大时间间隔(如吧1ms级别提升到10ms级别等),但是有一个究极问题无法解决,就是数字太大,睡眠时间过久,想一想,即使睡ms级别。int最大为1e9级别,1e9ms就是1e6s,约等于16666分钟,277小时,11.5天。

小伙子,听说你要用睡眠排序,我先让你11天。

二:猴子排序

原文链接:https://www.cnblogs.com/wangbingc/p/10205560.html

原理:根据无限猴子定律,在无穷长的时间后,即使是随机打字的猴子也可以打出一些有意义的单词,比如,cat, dog。因此,可以类推,会有一个足够幸运的猴子或连续或不连续地打出一本书,即使其几率比连续抓到一百次同花顺还要低。但在足够长的时间(长到你数不清它的秒数有多少位)后,其发生是必定的。
在这里每次都随机交换数组中的任意两个数字,在有限的时间内,一定可以让数组成为有序状态。

代码如下:

package mainimport ("fmt""math/rand""time"
)
//生成随机种子
func randInit() {rand.Seed(time.Now().Unix())
}
//判断是否有序
func isSorted(arr []int, len int) (sorted bool){for i := 0; i < len - 1; i++ {if arr[i + 1] < arr[i] {return false}}return true
}func main() {arr := []int{4, 3, 6, 8, 1, 5, 2, 9, 7, 11, 10} //数组长度为11耗时已经达到了s级别n := len(arr)randInit()time1 := time.Now()for ; !isSorted(arr, n); {randNum1 := rand.Int() % nrandNum2 := rand.Int() % n//防止相同发生无效交换if randNum2 == randNum1 {randNum1 = (randNum1 + 1) % n}arr[randNum1], arr[randNum2] = arr[randNum2], arr[randNum1]}time2 := time.Now()for i := 0; i < n; i++ {fmt.Print(arr[i], " ")}//计算消耗时间fmt.Println("\ncost time:", time2.Sub(time1).String())return
}

结果如下:

我测试了一下,数组长度为10以下,消耗的时间一般小于1s,但是随着数组长度继续增大,花费的时间会呈指数级别增长。
而且我们可以预想到随着数组长度继续增长,判断数组是否有序(isSorted函数)会成为最花费时间的地方。

顺便说一下,在笔者写到这里的时候,13个数组长度的猴子排序还没有结果…

总结:其实这两种方法都不是实用的方法,不过脑洞确实十分之大,慎用!!!

两种有趣的排序方法:睡眠排序、猴子排序(golang版本)相关推荐

  1. JDK四种常见线程池及使用场景、两种提交任务的方法

    转载:JDK 提供的线程池及使用场景 - 编程猎人 (programminghunter.com) 目录 四种常见线程池 1.newFixedThreadPool 2.newSingleThreadE ...

  2. golang java rpc_golang两种调用rpc的方法

    本文实例讲述了golang两种调用rpc的方法.分享给大家供大家参考,具体如下: golang的rpc有两种方法进行调用,一种是rpc例子中给的: package main import ( &quo ...

  3. 一文带你了解两种Transformer文字识别方法

    摘要:受Transformer模型的启发,目前一些学者将该结构应用到文本行识别中,以替代RNN,取得了良好的效果,如在HGA-STR和 SRN. 当前的文本行识别器为拥有更强的序列语义能力,模型多采用 ...

  4. 英雄无敌6服务器在哪个文件夹,Win7系统无法运行英雄无敌6的两种原因和解决方法...

    英雄无敌6作为一款策略模拟类游戏,深受高端玩家的喜爱.但最近有Win7旗舰版系统用户在玩英雄无敌6时,却出现了无法运行的情况,重启好多次还是一样,不太清楚是哪里出问题,网上相关解决方案也比较少,针对此 ...

  5. 两种ps切图方法(图层/切片)

    两种Ps切图方法 一.      基础操作: a)    Ctrl++ 放大图片,ctrl - -缩小图片 b)    按住空格键space+,点击鼠标左键,拖动图片. c)    修改单位,点击编辑 ...

  6. 归一化mysql函数_数据归一化和两种常用的归一化方法

    数据归一化和两种常用的归一化方法 一.总结 一句话总结: min-max标准化:x* =(x-min)/(max-min):新数据加入,需重新计算max和min Z-score标准化:x* =(x-μ ...

  7. win7 计算机名称 ip6,Win7系统提示ipv6无网络访问权限的两种原因及解决方法

    Win7系统提示ipv6无网络访问权限,导致无法上网,这该如何解决呢?ipv6无网络访问权限的原因有很多种,针对此问题,下面脚本之家的教大家解决ipv6无网络访问权限的问题,大家一起来看看吧. 故障原 ...

  8. 利用网络信息减少因果推断中的confounding bias--结合两种思路的新方法

    点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入! 本期AI TIME PhD专场,我们有幸邀请到了来自亚利桑那州立大学的博士生郭若城,为我们带来他的精彩分享--利用网络信息减少因果推断中 ...

  9. 数据归一化和两种常用的归一化方法

    数据标准化(归一化)处理是数据挖掘的一项基础工作,不同评价指标往往具有不同的量纲和量纲单位,这样的情况会影响到数据分析的结果,为了消除指标之间的量纲影响,需要进行数据标准化处理,以解决数据指标之间的可 ...

  10. 第 4 章 容器 - 023 - 两种进入容器的方法

    两种进入容器的方法 docker attach 通过 docker attach 可以 attach 到容器启动命令的终端,例如: 1 root@ubuntu:~# docker run -d ubu ...

最新文章

  1. Debugging JTAG
  2. opencv-contrib配置过程
  3. 关于计算机三个人的英语对话,关于三个人的英语对话
  4. jQuery系列(十四):jQuery中的ajax
  5. leetcode421. 数组中两个数的最大异或值(贪心算法)
  6. 数字签名,数字证书,证书链原理
  7. 爱因斯坦最熟悉的中国人,曾被学校开除的自学天才周培源
  8. 选择Eclipse 的列编辑模式
  9. 一款微信小程序商城项目(附源码)
  10. vue2+vant2搭建H5框架
  11. 左耳朵耗子:公司监控员工行为,这事逻辑就不对
  12. android studio 如何修改app名字、修改app图标
  13. vnr懒人版教程_vnr整合版下载-vnr懒人版最新版免费版 - 极光下载站
  14. Android 10 SystemUI中Android.bp文件中集成第三方JAR包或者so文件的方法
  15. 大数据技术如何有效阻击网络黑产?
  16. 乐高大颗粒作品19:端午节做一个粽子
  17. 三角形黑盒测试-Java Swing
  18. python忽略警告错误
  19. rpm 安装MySQL8
  20. Chrome浏览器无法启动,因为应用程序的并行配置不正确

热门文章

  1. 微信开放平台修改应用名称
  2. RuntimeError:The size of tensor a (100) must match the size of tensor b (12800) at non-singleton di
  3. php如何更改文件名后缀名,php如何修改文件后缀名
  4. 如何实现手机注册验证
  5. DNS域名解析过程剖析
  6. mro python_Python的mro
  7. php 转换带声调的字幕,PHP 汉字、拼音、unicode、声母、韵母互相转换
  8. python实现12306抢票,春节不用担心买不到票回家了
  9. K米在线超市实施步骤及检查列表
  10. 从毕业生到高级工程师:三位腾讯高级程序员的感悟