小朋友丢手帕问题,小朋友的编号(1,2,...,n) ,从k号小朋友开始数,从1开始数到m,当数到m的小朋友出列(1<m<n),问从k号小朋友开始数m,最后剩下几号小朋友?
这里有几点需要注意:
1、链表的头指针不能动,动了就找不着头了$head,一般用一个辅助指针指向头$cur=$head;
2、链表的往后指,在while循环里不要忘了一句话$cur=$cur->next;否则while($cur->next!=null)就死循环了
3、引用传递 在使用addHero时&$first 好好理解引用传递的含义
以下是php的环形链表实现方法
<html>
<head>
<meta http-equiv='content-type' content='text/html;charset=gbk'/>
</head>
<h1>约瑟夫问题</h1>
<?php
class Child{
public $no;
public $next=null;
public function __construct($no){
$this->no=$no;
}
}
//定义一个指向第一个小朋友的引用
$first=null;
$n=4;//$n表示有几个小朋友
//写一个函数来创建一个四个小朋友的环形链表;
/**
addChild函数的作用是:把$n个小孩构成一个环形链表,$first指向第一个孩子
*/
//引用传递
function addChild(&$first,$n){
//死去活来
//1.头结点不能动$first不能动
$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;
}
}
}
//遍历所有的小孩,显示:必须把头$first给函数.
function showChild($first){
//遍历$cur变量是帮助我们遍历环形链表的,所以不能动;
$cur=$first;
while($cur->next!=$first){
echo '<br/>小孩的编号是'.$cur->no;
$cur=$cur->next;
}
//当退出while循环时,已经到了环形链表的最后,最后还要处理一下最后一个小孩
echo '<br/>小孩的编号是'.$cur->no;
}
//问题简化,从第一个小孩开始数,数2,看看出圈的顺序
$m=3;
$k=2;
function countChild($first,$m,$k){
//思考:因为我们找到一个小孩,就要把他从环形链表中删除
//为了能够删除某个小孩,我们需要一个辅助变量,该变量指向的小孩在$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向后移动
//每移动一次,相当于数了两下;
//移动2次,相当于数了3下,因为自己数的时候是不需要动的
//当$tail =$first说明只有一个人了
while($tail!=$first){
for($i=0;$i<$m-1;$i++){
$tail=$tail->next;
$first=$first->next;
}
//把first指向的节点小孩删除环形链表
echo '<br/> 出圈的编号是'.$first->no;
$first=$first->next;
$tail->next=$first;
}
echo '<br/> 最后剩下的编号是'.$tail->no;
}
addChild($first,$n);
showChild($first);
countChild($first,$m,$k);
?>
</html>