两种有趣的排序方法:睡眠排序、猴子排序(golang版本)
前几天看到一个博主翻译的一个算法,叫睡眠排序,原文链接: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版本)相关推荐
- JDK四种常见线程池及使用场景、两种提交任务的方法
转载:JDK 提供的线程池及使用场景 - 编程猎人 (programminghunter.com) 目录 四种常见线程池 1.newFixedThreadPool 2.newSingleThreadE ...
- golang java rpc_golang两种调用rpc的方法
本文实例讲述了golang两种调用rpc的方法.分享给大家供大家参考,具体如下: golang的rpc有两种方法进行调用,一种是rpc例子中给的: package main import ( &quo ...
- 一文带你了解两种Transformer文字识别方法
摘要:受Transformer模型的启发,目前一些学者将该结构应用到文本行识别中,以替代RNN,取得了良好的效果,如在HGA-STR和 SRN. 当前的文本行识别器为拥有更强的序列语义能力,模型多采用 ...
- 英雄无敌6服务器在哪个文件夹,Win7系统无法运行英雄无敌6的两种原因和解决方法...
英雄无敌6作为一款策略模拟类游戏,深受高端玩家的喜爱.但最近有Win7旗舰版系统用户在玩英雄无敌6时,却出现了无法运行的情况,重启好多次还是一样,不太清楚是哪里出问题,网上相关解决方案也比较少,针对此 ...
- 两种ps切图方法(图层/切片)
两种Ps切图方法 一. 基础操作: a) Ctrl++ 放大图片,ctrl - -缩小图片 b) 按住空格键space+,点击鼠标左键,拖动图片. c) 修改单位,点击编辑 ...
- 归一化mysql函数_数据归一化和两种常用的归一化方法
数据归一化和两种常用的归一化方法 一.总结 一句话总结: min-max标准化:x* =(x-min)/(max-min):新数据加入,需重新计算max和min Z-score标准化:x* =(x-μ ...
- win7 计算机名称 ip6,Win7系统提示ipv6无网络访问权限的两种原因及解决方法
Win7系统提示ipv6无网络访问权限,导致无法上网,这该如何解决呢?ipv6无网络访问权限的原因有很多种,针对此问题,下面脚本之家的教大家解决ipv6无网络访问权限的问题,大家一起来看看吧. 故障原 ...
- 利用网络信息减少因果推断中的confounding bias--结合两种思路的新方法
点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入! 本期AI TIME PhD专场,我们有幸邀请到了来自亚利桑那州立大学的博士生郭若城,为我们带来他的精彩分享--利用网络信息减少因果推断中 ...
- 数据归一化和两种常用的归一化方法
数据标准化(归一化)处理是数据挖掘的一项基础工作,不同评价指标往往具有不同的量纲和量纲单位,这样的情况会影响到数据分析的结果,为了消除指标之间的量纲影响,需要进行数据标准化处理,以解决数据指标之间的可 ...
- 第 4 章 容器 - 023 - 两种进入容器的方法
两种进入容器的方法 docker attach 通过 docker attach 可以 attach 到容器启动命令的终端,例如: 1 root@ubuntu:~# docker run -d ubu ...
最新文章
- Debugging JTAG
- opencv-contrib配置过程
- 关于计算机三个人的英语对话,关于三个人的英语对话
- jQuery系列(十四):jQuery中的ajax
- leetcode421. 数组中两个数的最大异或值(贪心算法)
- 数字签名,数字证书,证书链原理
- 爱因斯坦最熟悉的中国人,曾被学校开除的自学天才周培源
- 选择Eclipse 的列编辑模式
- 一款微信小程序商城项目(附源码)
- vue2+vant2搭建H5框架
- 左耳朵耗子:公司监控员工行为,这事逻辑就不对
- android studio 如何修改app名字、修改app图标
- vnr懒人版教程_vnr整合版下载-vnr懒人版最新版免费版 - 极光下载站
- Android 10 SystemUI中Android.bp文件中集成第三方JAR包或者so文件的方法
- 大数据技术如何有效阻击网络黑产?
- 乐高大颗粒作品19:端午节做一个粽子
- 三角形黑盒测试-Java Swing
- python忽略警告错误
- rpm 安装MySQL8
- Chrome浏览器无法启动,因为应用程序的并行配置不正确
热门文章
- 微信开放平台修改应用名称
- RuntimeError:The size of tensor a (100) must match the size of tensor b (12800) at non-singleton di
- php如何更改文件名后缀名,php如何修改文件后缀名
- 如何实现手机注册验证
- DNS域名解析过程剖析
- mro python_Python的mro
- php 转换带声调的字幕,PHP 汉字、拼音、unicode、声母、韵母互相转换
- python实现12306抢票,春节不用担心买不到票回家了
- K米在线超市实施步骤及检查列表
- 从毕业生到高级工程师:三位腾讯高级程序员的感悟