<html> <head> <meta http-equiv=‘content-type‘ content=‘text/html;charset=utf-8‘ /> </head> <body> <h1>约瑟夫问题解决</h1> <?php class Child { public $no; public $next = null; public function __construct($no=‘‘){ $this->no = $no; } } // 定义一个指向第一个小朋友的引用 $first = null; $n = 4; // 表示有几个小朋友 // 写一个函数来创建4个小朋友的环形链表 // 深入分析下$first参数为什么加地址符& // 作用:把n个小孩构建出一个环形链表 // $first变量指向了第一个小朋友 function addChild(&$first,$n){ // 1.头结点不能动 $cur = null; for ($i = 0; $i < $n; $i++) { $child = new Child($i+1); // 怎么构成一个环形链表 if ($i==0) { $first = $child; $first->next = $child; $cur = $first; }else { $cur->next = $child; $child->next = $first; $cur = $cur->next; } } } // 显示环形链表中的所有小朋友 // 必须要把头给出来 function showChild($first){ // 遍历 $cur = $first; while($cur->next!=$first){ // 显示 echo ‘小孩的编号是‘.$cur->no.‘<br />‘; $cur = $cur->next; } // 当退出while循环时,已经到了环形链表的最后 // 所以还要处理下最后这个小孩节点 echo ‘小孩的编号是‘.$cur->no.‘<br />‘; } $m = 3; // 数3下 $k = 2; // 从第2个开始数 // 问题简化,从第一个小孩开始数,数2 // 看看出圈的顺序 function countChild($first,$m,$k){ if ($k>$m) { exit(‘数据设定不对‘); } // 思考:找到一个小孩,就要把他从环形链表踢出去 // 为了能够删除某个小孩,需要一个辅助变量 // 该变量指向的小孩在$first前面 $tail = $first; while($tail->next!=$first){ $tail = $tail->next; } // 考虑是从第几个人开始数数 for ($i = 0; $i < $k-1; $i++) { $tail = $tail->next; $first = $first->next; } // 当退出while循环时候 $tail就指向了最后这个小孩 // 让$first和$tail向后移动 // 每移动1次,相当于数了2下 // 移动2次,相当于数了3下 // 因为自己数的时候是不需要动的 // 当$tail==$first说明只有一个人 while($tail!=$first){ for ($i = 0; $i < $m-1; $i++) { $tail = $tail->next; $first = $first->next; } // 打印出出列小孩编号 echo ‘出圈人的编号是‘.$first->no.‘<br />‘; // 把$first指向的节点小孩删除环形链表 $first = $first->next; $tail->next = $first; } echo ‘最后留在圈圈的人的编号是‘.$tail->no; } addChild($first,4); showChild($first); // 真正的来玩儿游戏 if ($m<$n) { countChild($first,$m,$k); } ?> </body> </html>
原文:http://my.oschina.net/u/946060/blog/294963