无聊闲做,从使用PHP数组实现约瑟夫环问题谈性能
2010-10-18 12:16
585 查看
闲来无事,看到园子里的一篇文章约瑟夫环问题的 PHP 实现--使用 PHP 数组内部指针操作函数,以前没有搞过,也没有听说什么什么环的,所以突然也想搞一下试试
问题大概这样子:一群猴子排成一圈,按 1,2,...,n 依次编号。然后从第 1 只开始数,数到第 m 只,把它踢出圈,从它后面再开始数, 再数到第 m 只,在把它踢出去...,如此不停的进行下去, 直到最后只剩下一只猴子为止,那只猴子就叫做大王。要求编程模拟此过程,输入 m、n, 输出最后那个大王的编号。
脑子比较直,所以第一个想法就是这n只首尾相接排成环状的猴子,不就是一个环状链表吗? 用C的话,马上就是这个概念了。但是PHP里面没有这东西,也不能定义结构体,如果用类来实现,实际上开销有点大好像。剩下来现成点的就是数组了,虽然php中的数组实际上就是哈希表,开销也远大于C中的数组,不过,能想到的就是这家伙了。
原来的兄弟是用prev,next等函数来操作,但是顾名思义,prev、next每次它只能前进一步、后退一步,这样实际上就无法避免要使用循环,例如往后6个,就要运行6次的next,所以,在性能上是不划算的。很抱歉,我是用虚拟主机用惯的人,太过计较一点性能上的浪费,没办法,苦日子过惯了,见不得奢侈。
先申明一点,我并没有任何别的意思,原来的兄弟也说了只是想实现下并未注重算法性能。
换一个角度看,假设说现在圈里面有5个人,我们要数12个,那么我们真的要一个一个去数,数6下?不要吧,相信大家都知道只要数2个,因为其中的10次实际上就是对圈里的5人数了2圈,在这期间,没有人会被踢出去,换句话说,这10次就是白数的。真正决定的,是后面的2次,所以,换一个方法如下:
换句话说,就是array_splice在移除元素之后,会对索引做一个重排,所以,在不影响使用的情况下,尽量使用unset来取代array_splice,即使是一次需要移除多个元素的情况。我这里要它重排下,所以只能依了它。
最终,运行的结果如下
在10人中数6人的情况
在人数及数人的数量增多的情况下,循环带来的开销会更明显,例如100人数81
也是过苦日子的兄弟,可以参考 优化php代码的40条建议
问题大概这样子:一群猴子排成一圈,按 1,2,...,n 依次编号。然后从第 1 只开始数,数到第 m 只,把它踢出圈,从它后面再开始数, 再数到第 m 只,在把它踢出去...,如此不停的进行下去, 直到最后只剩下一只猴子为止,那只猴子就叫做大王。要求编程模拟此过程,输入 m、n, 输出最后那个大王的编号。
脑子比较直,所以第一个想法就是这n只首尾相接排成环状的猴子,不就是一个环状链表吗? 用C的话,马上就是这个概念了。但是PHP里面没有这东西,也不能定义结构体,如果用类来实现,实际上开销有点大好像。剩下来现成点的就是数组了,虽然php中的数组实际上就是哈希表,开销也远大于C中的数组,不过,能想到的就是这家伙了。
原来的兄弟是用prev,next等函数来操作,但是顾名思义,prev、next每次它只能前进一步、后退一步,这样实际上就无法避免要使用循环,例如往后6个,就要运行6次的next,所以,在性能上是不划算的。很抱歉,我是用虚拟主机用惯的人,太过计较一点性能上的浪费,没办法,苦日子过惯了,见不得奢侈。
先申明一点,我并没有任何别的意思,原来的兄弟也说了只是想实现下并未注重算法性能。
换一个角度看,假设说现在圈里面有5个人,我们要数12个,那么我们真的要一个一个去数,数6下?不要吧,相信大家都知道只要数2个,因为其中的10次实际上就是对圈里的5人数了2圈,在这期间,没有人会被踢出去,换句话说,这10次就是白数的。真正决定的,是后面的2次,所以,换一个方法如下:
//转自/article/6376604.html function getKingMonkey($n, $m) { $a = array();//声明内部数组 for($i = 1; $i <= $n; $i ++) { $a[$i] = $i;//这一步是对号入座 } reset($a);//为了严谨,我们来一个 reset() 函数,其实也可以省去 while(count($a) > 1)//主循环开始,这里使用的判别条件是数组元素的个数等于 1 的时候停止循环 { for($counter = 1; $counter <= $m; $counter++)//嵌套的 for 循环,用来“踢出”数到 m 的猴子 { if(next($a)){//如果存在 next 元素 if($counter == $m) { unset($a[array_search(prev($a), $a)]);//当数到 m 时,使用 unset() 删除数组元素 } } else//如果不存在 next 元素 { reset($a);//则数组的第一个元素充当 next 元素 if($counter == $m) { unset($a[array_search(end($a), $a)]);//当数到 m 时,使用 unset() 删除数组元素,注意这里是 end() reset($a);//记得让数组内部指针“归位” } } } } return current($a); }
一、首先,用for循环为数组赋连续的值,是不划算的,用内置的range函数,就可以实现。
二、尽量避免多次调用count来获取数组数量,php中获取数组数量的方法和c#中不同,不如其高效,多次使用时,请使用局部变量来记录
三、在逻辑结构允许的情况下,++$t远比$t--来的合算,因为这点上,php是特殊的,像$t++,$t--这类的结构,它内部实际上多使用了一个局部变量来记录原值,所以,要多执行一个opcode
四、至于为什么踢出去的时候,使用array_splice而不用unset呢? 虽然unset属于语法结构,速度远比array_splice这种函数调用来的快,也都是可以将数组中的一个元素移除,但是,他们还是有不同之处。array_splice在移除数组的同时,会更改其后面索引类型为数字的元素的索引,而unset则不会。如
$a=array(0,1,'a'=>4,2,3,4,5,6);
array_splice($a,1,1);
则结构就由原来的
array
0 => int 0
1 => int 1
'a' => int 4
2 => int 2
3 => int 3
4 => int 4
5 => int 5
6 => int 6
变为:
array
0 => int 0
'a' => int 4
1 => int 2
2 => int 3
3 => int 4
4 => int 5
5 => int 6
换句话说,就是array_splice在移除元素之后,会对索引做一个重排,所以,在不影响使用的情况下,尽量使用unset来取代array_splice,即使是一次需要移除多个元素的情况。我这里要它重排下,所以只能依了它。
最终,运行的结果如下
在10人中数6人的情况
在人数及数人的数量增多的情况下,循环带来的开销会更明显,例如100人数81
也是过苦日子的兄弟,可以参考 优化php代码的40条建议
相关文章推荐
- python中使用queue实现约瑟夫环(约瑟夫问题)求解
- javascript中使用循环链表实现约瑟夫环问题
- 使用链表实现环结构以解决约瑟夫环问题
- 约瑟夫环问题的PHP实现 使用PHP数组内部指针操作函数
- 约瑟夫环问题的 PHP 实现--使用 PHP 数组内部指针操作函数
- 约瑟夫环问题的PHP实现 使用PHP数组内部指针操作函数
- 使用mssql2008新特性(存储过程参数类型使用"用户自定义表"来实现批量DML更新多表)解决项目里遇到的性能问题
- 去哪儿网大数据流处理系统:如何使用Alluxio(前 Tachyon)实现10倍性能提升
- 循环单链表实现约瑟夫环问题
- PHP使用之上传文件到本地服务器(实现上传文件后页面内容不动、解决上传文件命名乱码后缀问题)
- 约瑟夫环问题(Josephus Problem)C程序实现
- 基于.NET的分词软件设计与实现V2.0--性能问题说明及功能增强
- Android 性能优化之使用MAT分析内存泄露问题
- 使用bootstrap typeahead插件实现输入框自动补全之问题及解决办法
- 对JavaEE的十大不当使用导致的性能问题
- 用C++数组实现约瑟夫环问题
- 在MID使用Gnome Canvas实现连续的仿射变换的问题
- 关于使用图片轮播插件无法实现效果的问题
- Redis中keys命令的使用与带来的性能问题
- 【C/S通信交互之Http篇】Cocos2dx(Client)使用Curl与Jetty(Server)实现手机网游Http通信框架(内含解决curl.h头文件找不到问题)