<div class="htmledit_views">
文西马龙:http://blog.csdn.net/wenximalong/
现在我们对单链表有了基本的了解,现在学习一下环形链表。
环形链表的内存示意图
环形链表的好处:可以模拟许多实际的情景
如丢手帕问题,就是经典的用环形链表来解决的
现在我们来完成约瑟夫问题的解决方案!
Josephu问题
Josephu问题为:射编号为1,2,…n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。并求出最后出列的人是哪个?
提示:用一个不带头节点的循环链表来处里Josephu问题,先构成一个有n个节点的单循环链表,然后由k节点起从1开始计数,计到m时,对应节点从链表中删除,然后再从被删除节点的下一个节点又从1开始计数,直到最后一个节点从链表中删除算法结束。
思路:
(一)构建一个环形链表,链表上的每个节点,表示一个小朋友(PHP语言实现)
一个小朋友的情况
两个小朋友的情况
当第一个结点做完以后,1号小朋友还有一个新的指向指向它,就是cur。cur的用处,当有2号小朋友的时候,cur就发挥作用了,此时cur还是指向1号小朋友,那么cur->next=child;则①号线就被搭起来了,然后child->next=first;则②号线就被搭起来了,2号小朋友结点就指向了1号小朋友结点,环形链表就形成了。
(二)写一个函数来显示所有的小孩子
josephu.php
- <html>
- <head>
- <meta http-equiv=”Content-Type” content=“text/html; charset=gb2312” />
- </head>
- <body>
- <h1>约瑟夫问题解决</h1>
- <?php
- //先构建一个环形链表,链表上的每个节点,表示一个小朋友
- //小孩类
- class Child{
- public no</span><span>; </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="vars">;
- public next=null;
- //构造函数
- public function __construct(no</span><span>){ </span></span></li><li class="alt"><span> <span class="vars">$this</span><span>->no=</span><span class="vars">$no</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">//定义一个指向第一个小朋友的引用</span><span> </span></span></li><li class="alt"><span> <span class="comment">//定义一个空头</span><span> </span></span></li><li class=""><span> <span class="vars">){
- $this->no=$no;
- }
- }
- //定义一个指向第一个小朋友的引用
- //定义一个空头
- first=null;
- n</span><span>=4; </span><span class="comment">//=4; //n表示有几个小朋友
- //写一个函数来创建一个四个小朋友的环形链表
- /*
- addChild函数的作用是:把
n个小孩在构建成一个环形链表, first变量就指向该环形链表的第一个小孩子 - */
- function addChild(&
first</span><span>,</span><spanclass="vars"> ,n){ //此处要加地址符 - //1.头结点不能动 first不能动</span><span> </span></span></li><li class=""><span> <span class="vars">
- cur=first</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">for</span><span>(</span><span class="vars">;
- for(i=0;i</span><span><</span><span class="vars"><n;i</span><span>++){ </span></span></li><li class=""><span> <span class="vars">$child</span><span>=</span><span class="keyword">new</span><span> Child(</span><span class="vars">$i</span><span>+1); </span><span class="comment">//为什么要加1,因为for循环中i是从开始的,但是小朋友的编号是从1开始的</span><span> </span></span></li><li class="alt"><span> <span class="comment">//怎么构成一个环形链表呢</span><span> </span></span></li><li class=""><span> <span class="keyword">if</span><span>(</span><span class="vars">$i</span><span>==0){ </span><span class="comment">//第一个小孩的情况</span><span> </span></span></li><li class="alt"><span> <span class="vars">$first</span><span>=</span><span class="vars">$child</span><span>; </span><span class="comment">//让first指向child,但是还没有构建环形链表</span><span> </span></span></li><li class=""><span> <span class="vars">$first</span><span>->next=</span><span class="vars">$child</span><span>; </span><span class="comment">//自己指向自己</span><span> </span></span></li><li class="alt"><span> <span class="vars">$cur</span><span>=</span><span class="vars">$first</span><span>; </span></span></li><li class=""><span> }<span class="keyword">else</span><span>{ </span></span></li><li class="alt"><span> <span class="vars">$cur</span><span>->next=</span><span class="vars">$child</span><span>; </span></span></li><li class=""><span> <span class="vars">$child</span><span>->next=</span><span class="vars">$first</span><span>; </span></span></li><li class="alt"><span> <span class="comment">//继续指向下一个</span><span> </span></span></li><li class=""><span> <span class="vars">$cur</span><span>=</span><span class="vars">$cur</span><span>->next; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">//遍历所有的小孩,并显示</span><span> </span></span></li><li class="alt"><span> <span class="keyword">function</span><span> showChild(</span><span class="vars">++){
- $child=new Child($i+1); //为什么要加1,因为for循环中i是从开始的,但是小朋友的编号是从1开始的
- //怎么构成一个环形链表呢
- if($i==0){ //第一个小孩的情况
- $first=$child; //让first指向child,但是还没有构建环形链表
- $first->next=$child; //自己指向自己
- $cur=$first;
- }else{
- $cur->next=$child;
- $child->next=$first;
- //继续指向下一个
- $cur=$cur->next;
- }
- }
- }
- //遍历所有的小孩,并显示
- function showChild(first){
- //遍历 cur变量是帮助我们遍历循环列表的,所以不能动
-
cur</span><span>=</span><spanclass="vars"> =first; - while(cur</span><span>->next!=</span><span class="vars">->next!=first){ //cur没有到结尾,就遍历
- //显示
- echo‘<br/>小孩的编号是’.cur</span><span>->no; </span></span></li><li class="alt"><span> <span class="comment">//继续</span><span> </span></span></li><li class=""><span> <span class="vars">->no;
- //继续
- cur=cur</span><span>->next; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> addChild(<span class="vars">->next;
- }
- }
- addChild(first,n</span><span>); </span></span></li><li class=""><span> showChild(<span class="vars">);
- showChild(first);
- ?>
- </body>
- </html>
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> </head> <body> <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=$first; for($i=0;$i<$n;$i++){ $child=new Child($i+1); //为什么要加1,因为for循环中i是从开始的,但是小朋友的编号是从1开始的 //怎么构成一个环形链表呢 if($i==0){ //第一个小孩的情况 $first=$child; //让first指向child,但是还没有构建环形链表 $first->next=$child; //自己指向自己 $cur=$first; }else{ $cur->next=$child; $child->next=$first; //继续指向下一个 $cur=$cur->next; } } } //遍历所有的小孩,并显示 function showChild($first){ //遍历 cur变量是帮助我们遍历循环列表的,所以不能动 $cur=$first; while($cur->next!=$first){ //cur没有到结尾,就遍历 //显示 echo'<br/>小孩的编号是'.$cur->no; //继续 $cur=$cur->next; } } addChild($first,$n); showChild($first); ?> </body> </html>
为什么现在只显示三个小孩呢,分析一下代码在内存中是怎么运作的
图片大,在新窗口中打开图片,观看完整图片
(1)语句①执行后,cur也指向了1号小朋友;
(2)然后语句②执行,进入while循环,此时cur指向1号小朋友,执行语句③,输出:小孩的编号是1,再执行语句④
(3)此时cur指向2号小朋友,然后语句②执行,进入while循环,此时cur指向2号小朋友,执行语句③,输出:小孩的编号是2,再执行语句④
(4)此时cur指向3号小朋友,,然后语句②执行,进入while循环,此时cur指向3号小朋友,执行语句③,输出:小孩的编号是3,再执行语句④
(5)此时cur指向4号小朋友,然后执行语句②,此时 cur->next,就指向了1号小朋友,而first也指向1号小朋友,此时 cur->next!=$first;不成立了,为假,就退出了while循环, 因此就少了一个小孩,即4号小朋友。
所以要对josephu.php修改,即josephu2.php
josephu2.php
- <html>
- <head>
- <meta http-equiv=”Content-Type” content=“text/html; charset=gb2312” />
- </head>
- <body>
- <h1>约瑟夫问题解决</h1>
- <?php
- //先构建一个环形链表,链表上的每个节点,表示一个小朋友
- //小孩类
- class Child{
- public no</span><span>; </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="vars">;
- public next=null;
- //构造函数
- public function __construct(no</span><span>){ </span></span></li><li class="alt"><span> <span class="vars">$this</span><span>->no=</span><span class="vars">$no</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">//定义一个指向第一个小朋友的引用</span><span> </span></span></li><li class="alt"><span> <span class="comment">//定义一个空头</span><span> </span></span></li><li class=""><span> <span class="vars">){
- $this->no=$no;
- }
- }
- //定义一个指向第一个小朋友的引用
- //定义一个空头
- first=null;
- n</span><span>=4; </span><span class="comment">//=4; //n表示有几个小朋友
- //写一个函数来创建一个四个小朋友的环形链表
- /*
- addChild函数的作用是:把
n个小孩在构建成一个环形链表, first变量就指向该环形链表的第一个小孩子 - */
- function addChild(&
first</span><span>,</span><spanclass="vars"> ,n){ //此处要加地址符 - //1.头结点不能动 first不能动</span><span> </span></span></li><li class=""><span> <span class="vars">
- cur=first</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">for</span><span>(</span><span class="vars">;
- for(i=0;i</span><span><</span><span class="vars"><n;i</span><span>++){ </span></span></li><li class=""><span> <span class="vars">$child</span><span>=</span><span class="keyword">new</span><span> Child(</span><span class="vars">$i</span><span>+1); </span><span class="comment">//为什么要加1,因为for循环中i是从开始的,但是小朋友的编号是从1开始的</span><span> </span></span></li><li class="alt"><span> <span class="comment">//怎么构成一个环形链表呢</span><span> </span></span></li><li class=""><span> <span class="keyword">if</span><span>(</span><span class="vars">$i</span><span>==0){ </span><span class="comment">//第一个小孩的情况</span><span> </span></span></li><li class="alt"><span> <span class="vars">$first</span><span>=</span><span class="vars">$child</span><span>; </span><span class="comment">//让first指向child,但是还没有构建环形链表</span><span> </span></span></li><li class=""><span> <span class="vars">$first</span><span>->next=</span><span class="vars">$child</span><span>; </span><span class="comment">//自己指向自己</span><span> </span></span></li><li class="alt"><span> <span class="vars">$cur</span><span>=</span><span class="vars">$first</span><span>; </span></span></li><li class=""><span> }<span class="keyword">else</span><span>{ </span></span></li><li class="alt"><span> <span class="vars">$cur</span><span>->next=</span><span class="vars">$child</span><span>; </span></span></li><li class=""><span> <span class="vars">$child</span><span>->next=</span><span class="vars">$first</span><span>; </span></span></li><li class="alt"><span> <span class="comment">//继续指向下一个</span><span> </span></span></li><li class=""><span> <span class="vars">$cur</span><span>=</span><span class="vars">$cur</span><span>->next; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">//遍历所有的小孩,并显示</span><span> </span></span></li><li class="alt"><span> <span class="keyword">function</span><span> showChild(</span><span class="vars">++){
- $child=new Child($i+1); //为什么要加1,因为for循环中i是从开始的,但是小朋友的编号是从1开始的
- //怎么构成一个环形链表呢
- if($i==0){ //第一个小孩的情况
- $first=$child; //让first指向child,但是还没有构建环形链表
- $first->next=$child; //自己指向自己
- $cur=$first;
- }else{
- $cur->next=$child;
- $child->next=$first;
- //继续指向下一个
- $cur=$cur->next;
- }
- }
- }
- //遍历所有的小孩,并显示
- function showChild(first){
- //遍历 cur变量是帮助我们遍历循环列表的,所以不能动
-
cur</span><span>=</span><spanclass="vars"> =first; - while(cur</span><span>->next!=</span><span class="vars">->next!=first){ //cur没有到结尾,就遍历
- //显示
- echo‘<br/>小孩的编号是’.cur</span><span>->no; </span></span></li><li class="alt"><span> <span class="comment">//继续</span><span> </span></span></li><li class=""><span> <span class="vars">->no;
- //继续
- cur=cur</span><span>->next; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">//当退出while循环时,已经到了环形链表的最后,即cur此时指向最后一个小孩,所以还要处里一下最后这个小孩节点</span><span> </span></span></li><li class="alt"><span> <span class="func">echo</span><span class="string">'<br/>小孩的编号是'</span><span>.</span><span class="vars">->next;
- }
- //当退出while循环时,已经到了环形链表的最后,即cur此时指向最后一个小孩,所以还要处里一下最后这个小孩节点
- echo'<br/>小孩的编号是'.cur->no;
- }
- addChild(
first</span><span>,</span><spanclass="vars"> ,n); - showChild($first);
- ?>
- </body>
- </html>
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> </head> <body> <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=$first; for($i=0;$i<$n;$i++){ $child=new Child($i+1); //为什么要加1,因为for循环中i是从开始的,但是小朋友的编号是从1开始的 //怎么构成一个环形链表呢 if($i==0){ //第一个小孩的情况 $first=$child; //让first指向child,但是还没有构建环形链表 $first->next=$child; //自己指向自己 $cur=$first; }else{ $cur->next=$child; $child->next=$first; //继续指向下一个 $cur=$cur->next; } } } //遍历所有的小孩,并显示 function showChild($first){ //遍历 cur变量是帮助我们遍历循环列表的,所以不能动 $cur=$first; while($cur->next!=$first){ //cur没有到结尾,就遍历 //显示 echo'<br/>小孩的编号是'.$cur->no; //继续 $cur=$cur->next; } //当退出while循环时,已经到了环形链表的最后,即cur此时指向最后一个小孩,所以还要处里一下最后这个小孩节点 echo'<br/>小孩的编号是'.$cur->no; } addChild($first,$n); showChild($first); ?> </body>
</html>
注意:function addChild(&
修改的是值还是地址
test.php
- <html>
- <head>
- <meta http-equiv=”Content-Type” content=“text/html; charset=gb2312” />
- </head>
- <body>
- <h1>function addChild(&
first</span><span>,</span><spanclass="vars"> ,n){ //此处first前面为什么要加地址符&呢</h1></span><span> </span></span></li><li class="alt"><span> <?php </span></li><li class=""><span> <span class="keyword">class</span><span> Dog{ </span></span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="vars">$age</span><span>; </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">function</span><span> __construct(</span><span class="vars">$age</span><span>){ </span></span></li><li class="alt"><span> <span class="vars">$this</span><span>->age=</span><span class="vars">$age</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="keyword">function</span><span> test(</span><span class="vars"> - <?php
- class Dog{
- public $age;
- public function __construct($age){
- $this->age=$age;
- }
- }
- function test(dog){
- dog</span><span>->age=30; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="comment">//创建一个狗对象实例</span><span> </span></span></li><li class=""><span> <span class="vars">->age=30;
- }
- //创建一个狗对象实例
- dog1=new Dog(100);
- //调用test(调用函数就会开辟一个新栈)
- test(dog1</span><span>); </span></span></li><li class="alt"><span> </span></li><li class=""><span> <span class="func">echo</span><span> </span><span class="vars">);
- echo dog1->age; //为什么会输出30呢
- echo ‘<br/>’;
- function test2(dog</span><span>){ </span></span></li><li class=""><span> <span class="vars">$dog</span><span>=</span><span class="keyword">new</span><span> Dog(200); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">//创建一个狗对象实例</span><span> </span></span></li><li class="alt"><span> <span class="vars">){
- $dog=new Dog(200);
- }
- //创建一个狗对象实例
- dog1=new Dog(100);
- //调用test(调用函数就会开辟一个新栈)
- test2(dog1</span><span>); </span></span></li><li class=""><span> <span class="func">echo</span><span> </span><span class="vars">);
- echo dog1->age; //此时输出100还是200呢,输出100
- echo ‘<br/>’;
- //& 表示用地址传递
- function test3(&dog</span><span>){ </span></span></li><li class="alt"><span> <span class="vars">$dog</span><span>=</span><span class="keyword">new</span><span> Dog(200); </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="comment">//创建一个狗对象实例</span><span> </span></span></li><li class=""><span> <span class="vars">){
- $dog=new Dog(200);
- }
- //创建一个狗对象实例
- dog1=new Dog(100);
- //调用test(调用函数就会开辟一个新栈)
- test3(dog1</span><span>); </span></span></li><li class="alt"><span> <span class="func">echo</span><span> </span><span class="vars">);
- echo dog1->age; //此时输出100还是200呢,输出200
- ?>
- </body>
- </html>
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> </head> <body> <h1>function addChild(&$first,$n){ //此处$first前面为什么要加地址符&呢</h1> <?php class Dog{ public $age; public function __construct($age){ $this->age=$age; } } function test($dog){ $dog->age=30; } //创建一个狗对象实例 $dog1=new Dog(100); //调用test(调用函数就会开辟一个新栈) test($dog1); echo $dog1->age; //为什么会输出30呢 echo '<br/>'; function test2($dog){ $dog=new Dog(200); } //创建一个狗对象实例 $dog1=new Dog(100); //调用test(调用函数就会开辟一个新栈) test2($dog1); echo $dog1->age; //此时输出100还是200呢,输出100 echo '<br/>'; //& 表示用地址传递 function test3(&$dog){ $dog=new Dog(200); } //创建一个狗对象实例 $dog1=new Dog(100); //调用test(调用函数就会开辟一个新栈) test3($dog1); echo $dog1->age; //此时输出100还是200呢,输出200 ?> </body> </html>
内存分析图
图片大,在新窗口中打开图片,观看完整图片
(1)语句①执行完后,主栈里就会有一个dog1变量,dog1变量指向了一个堆,对象实例的数据是放在堆区的;
(2)然后执行语句②,调用函数,不管哪种语言,只要调用函数,就会开辟一个新栈,在新栈test栈中,在test栈区中有一个变量
再加深一下
内存分析图
图片大,在新窗口中打开图片,观看完整图片
(1)语句①执行完后,主栈里就会有一个dog1变量,dog1变量指向了一个堆,对象实例的数据是放在堆区的;
(2)然后执行语句②,调用函数,不管哪种语言,只要调用函数,就会开辟一个新栈,在新栈test2栈中,在test2栈区中有一个变量
现在考虑加入地址符&的情况
内存分析图
图片大,在新窗口中打开图片,观看完整图片
(1)语句①执行完后,主栈里就会有一个dog1变量,dog1变量指向了一个堆,对象实例的数据是放在堆区的;
(2)然后执行语句②,调用函数,不管哪种语言,只要调用函数,就会开辟一个新栈,在新栈test3栈中,在test3栈区中有一个变量
=========
(三)真正来玩游戏
(1)先问题简化,从第一个小孩开始数,数2,看看出列的顺序
分析图
现在我们已经有了环形链表,并且
让1号小朋友的next指向3号小朋友,2号就出列了。但是这个$first是指向了2号本身。所以单链表的麻烦事情: ★★它不能自己把自己删除掉。
因此必须保证
这个时候就可以把2号人物给删除了,先让
就是现在需要一个辅助指针,就是在运行之前,要先拿一个指针指向$first的前面,如下图所示
————-
josephu3.php
- <html>
- <head>
- <meta http-equiv=”Content-Type” content=“text/html; charset=gb2312” />
- </head>
- <body>
- <h1>约瑟夫问题解决</h1>
- <?php
- //先构建一个环形链表,链表上的每个节点,表示一个小朋友
- //小孩类
- class Child{
- public no</span><span>; </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="vars">;
- public next=null;
- //构造函数
- public function __construct(no</span><span>){ </span></span></li><li class="alt"><span> <span class="vars">$this</span><span>->no=</span><span class="vars">$no</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">//定义一个指向第一个小朋友的引用</span><span> </span></span></li><li class="alt"><span> <span class="comment">//定义一个空头</span><span> </span></span></li><li class=""><span> <span class="vars">){
- $this->no=$no;
- }
- }
- //定义一个指向第一个小朋友的引用
- //定义一个空头
- first=null;
- n</span><span>=4; </span><span class="comment">//=4; //n表示有几个小朋友
- //写一个函数来创建一个四个小朋友的环形链表
- /*
- addChild函数的作用是:把
n个小孩在构建成一个环形链表, first变量就指向该环形链表的第一个小孩子 - */
- function addChild(&
first</span><span>,</span><spanclass="vars"> ,n){ //此处要加地址符 - //1.头结点不能动
first不能动, cur=first;让cur来帮我们穿针引线</span><span> </span></span></li><li class=""><span> <span class="vars"> - cur=first</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">for</span><span>(</span><span class="vars">;
- for(i=0;i</span><span><</span><span class="vars"><n;i</span><span>++){ </span></span></li><li class=""><span> <span class="vars">$child</span><span>=</span><span class="keyword">new</span><span> Child(</span><span class="vars">$i</span><span>+1); </span><span class="comment">//为什么要加1,因为for循环中i是从开始的,但是小朋友的编号是从1开始的</span><span> </span></span></li><li class="alt"><span> <span class="comment">//怎么构成一个环形链表呢</span><span> </span></span></li><li class=""><span> <span class="keyword">if</span><span>(</span><span class="vars">$i</span><span>==0){ </span><span class="comment">//第一个小孩的情况</span><span> </span></span></li><li class="alt"><span> <span class="vars">$first</span><span>=</span><span class="vars">$child</span><span>; </span><span class="comment">//让first指向child,但是还没有构建环形链表</span><span> </span></span></li><li class=""><span> <span class="vars">$first</span><span>->next=</span><span class="vars">$child</span><span>; </span><span class="comment">//自己指向自己</span><span> </span></span></li><li class="alt"><span> <span class="vars">$cur</span><span>=</span><span class="vars">$first</span><span>; </span><span class="comment">//当$i==0的时候,就让cur和first指向同一个地方</span><span> </span></span></li><li class=""><span> }<span class="keyword">else</span><span>{ </span></span></li><li class="alt"><span> <span class="vars">$cur</span><span>->next=</span><span class="vars">$child</span><span>; </span></span></li><li class=""><span> <span class="vars">$child</span><span>->next=</span><span class="vars">$first</span><span>; </span></span></li><li class="alt"><span> <span class="comment">//继续指向下一个</span><span> </span></span></li><li class=""><span> <span class="vars">$cur</span><span>=</span><span class="vars">$cur</span><span>->next; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">//遍历所有的小孩,并显示</span><span> </span></span></li><li class="alt"><span> <span class="keyword">function</span><span> showChild(</span><span class="vars">++){
- $child=new Child($i+1); //为什么要加1,因为for循环中i是从开始的,但是小朋友的编号是从1开始的
- //怎么构成一个环形链表呢
- if($i==0){ //第一个小孩的情况
- $first=$child; //让first指向child,但是还没有构建环形链表
- $first->next=$child; //自己指向自己
- $cur=$first; //当$i==0的时候,就让cur和first指向同一个地方
- }else{
- $cur->next=$child;
- $child->next=$first;
- //继续指向下一个
- $cur=$cur->next;
- }
- }
- }
- //遍历所有的小孩,并显示
- function showChild(first){
- //遍历 cur变量是帮助我们遍历循环列表的,所以不能动
-
cur</span><span>=</span><spanclass="vars"> =first; - while(cur</span><span>->next!=</span><span class="vars">->next!=first){ //cur没有到结尾,就遍历
- //显示
- echo‘<br/>小孩的编号是’.cur</span><span>->no; </span></span></li><li class="alt"><span> <span class="comment">//继续</span><span> </span></span></li><li class=""><span> <span class="vars">->no;
- //继续
- cur=cur</span><span>->next; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">//当退出while循环时,已经到了环形链表的最后,即cur此时指向最后一个小孩,所以还要处里一下最后这个小孩节点</span><span> </span></span></li><li class="alt"><span> <span class="func">echo</span><span class="string">'<br/>小孩的编号是'</span><span>.</span><span class="vars">->next;
- }
- //当退出while循环时,已经到了环形链表的最后,即cur此时指向最后一个小孩,所以还要处里一下最后这个小孩节点
- echo'<br/>小孩的编号是'.cur->no;
- }
- //问题简化,从第一个小孩开始数,数2,看看出拳的顺序
- function countChild(first</span><span>){ </span></span></li><li class=""><span> <span class="comment">//思考:因为我们每找到一个小孩,就要把他从环形链表中删除</span><span> </span></span></li><li class="alt"><span> <span class="comment">//为了能够删除某个小孩,我们需要一个辅助变量,该变量指向的小孩在$first前面,在$first的前面,因为是环形的,就相当于在队尾了。</span><span> </span></span></li><li class=""><span> <span class="vars">$tail</span><span>=</span><span class="vars">$first</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">while</span><span>(</span><span class="vars">$tail</span><span>->next!=</span><span class="vars">$first</span><span>){ </span><span class="comment">//只要tail的next不等于first,就要tail不停的向下走,即$tail=$tail->next;</span><span> </span></span></li><li class=""><span> <span class="vars">$tail</span><span>=</span><span class="vars">$tail</span><span>->next; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">//上面的代码,就是生成指向最后一个小孩的$tail</span><span> </span></span></li><li class="alt"><span> <span class="comment">//当退出while时,我们的$tail就指向了最后这个小孩</span><span> </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="comment">//让$first和$tail向后移动</span><span> </span></span></li><li class=""><span> <span class="comment">//移一下就相当于数了两下,因为还要数自己一下</span><span> </span></span></li><li class="alt"><span> <span class="comment">//如从1号小朋友到2号小朋友,只移动了一下,那么是1号小朋友数1 再数2,因为还数了自己一下。</span><span> </span></span></li><li class=""><span> <span class="comment">//移动2次,相当于数了3下,因为自己数的时候,自己不需要动</span><span> </span></span></li><li class="alt"><span> <span class="keyword">while</span><span>(</span><span class="vars">$tail</span><span>!=</span><span class="vars">$first</span><span>){ </span><span class="comment">//当$tail==$first则说明只有最后一个人了</span><span> </span></span></li><li class=""><span> <span class="keyword">for</span><span>(</span><span class="vars">$i</span><span>=0;</span><span class="vars">$i</span><span><1;</span><span class="vars">$i</span><span>++){ </span></span></li><li class="alt"><span> <span class="vars">$tail</span><span>=</span><span class="vars">$tail</span><span>->next; </span></span></li><li class=""><span> <span class="vars">$first</span><span>=</span><span class="vars">$first</span><span>->next; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">//把$first指向的节点小孩删除环形链表</span><span> </span></span></li><li class="alt"><span> <span class="vars">$first</span><span>=</span><span class="vars">$first</span><span>->next; </span></span></li><li class=""><span> <span class="vars">$tail</span><span>->next=</span><span class="vars">$first</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="func">echo</span><span class="string">'<br/>最后留在圈圈的人的编号是'</span><span>.</span><span class="vars">$tail</span><span>->no; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> addChild(<span class="vars">){
- //思考:因为我们每找到一个小孩,就要把他从环形链表中删除
- //为了能够删除某个小孩,我们需要一个辅助变量,该变量指向的小孩在$first前面,在$first的前面,因为是环形的,就相当于在队尾了。
- $tail=$first;
- while($tail->next!=$first){ //只要tail的next不等于first,就要tail不停的向下走,即$tail=$tail->next;
- $tail=$tail->next;
- }
- //上面的代码,就是生成指向最后一个小孩的$tail
- //当退出while时,我们的$tail就指向了最后这个小孩
- //让$first和$tail向后移动
- //移一下就相当于数了两下,因为还要数自己一下
- //如从1号小朋友到2号小朋友,只移动了一下,那么是1号小朋友数1 再数2,因为还数了自己一下。
- //移动2次,相当于数了3下,因为自己数的时候,自己不需要动
- while($tail!=$first){ //当$tail==$first则说明只有最后一个人了
- for($i=0;$i<1;$i++){
- $tail=$tail->next;
- $first=$first->next;
- }
- //把$first指向的节点小孩删除环形链表
- $first=$first->next;
- $tail->next=$first;
- }
- echo'<br/>最后留在圈圈的人的编号是'.$tail->no;
- }
- addChild(first,n</span><span>); </span></span></li><li class=""><span> showChild(<span class="vars">);
- showChild(first);
- //真正来玩游戏
- countChild($first);
- ?>
- </body>
- </html>
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> </head> <body> <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=$first;让cur来帮我们穿针引线 $cur=$first; for($i=0;$i<$n;$i++){ $child=new Child($i+1); //为什么要加1,因为for循环中i是从开始的,但是小朋友的编号是从1开始的 //怎么构成一个环形链表呢 if($i==0){ //第一个小孩的情况 $first=$child; //让first指向child,但是还没有构建环形链表 $first->next=$child; //自己指向自己 $cur=$first; //当$i==0的时候,就让cur和first指向同一个地方 }else{ $cur->next=$child; $child->next=$first; //继续指向下一个 $cur=$cur->next; } } } //遍历所有的小孩,并显示 function showChild($first){ //遍历 cur变量是帮助我们遍历循环列表的,所以不能动 $cur=$first; while($cur->next!=$first){ //cur没有到结尾,就遍历 //显示 echo'<br/>小孩的编号是'.$cur->no; //继续 $cur=$cur->next; } //当退出while循环时,已经到了环形链表的最后,即cur此时指向最后一个小孩,所以还要处里一下最后这个小孩节点 echo'<br/>小孩的编号是'.$cur->no; } //问题简化,从第一个小孩开始数,数2,看看出拳的顺序 function countChild($first){ //思考:因为我们每找到一个小孩,就要把他从环形链表中删除 //为了能够删除某个小孩,我们需要一个辅助变量,该变量指向的小孩在$first前面,在$first的前面,因为是环形的,就相当于在队尾了。 $tail=$first; while($tail->next!=$first){ //只要tail的next不等于first,就要tail不停的向下走,即$tail=$tail->next; $tail=$tail->next; } //上面的代码,就是生成指向最后一个小孩的$tail //当退出while时,我们的$tail就指向了最后这个小孩 //让$first和$tail向后移动 //移一下就相当于数了两下,因为还要数自己一下 //如从1号小朋友到2号小朋友,只移动了一下,那么是1号小朋友数1 再数2,因为还数了自己一下。 //移动2次,相当于数了3下,因为自己数的时候,自己不需要动 while($tail!=$first){ //当$tail==$first则说明只有最后一个人了 for($i=0;$i<1;$i++){ $tail=$tail->next; $first=$first->next; } //把$first指向的节点小孩删除环形链表 $first=$first->next; $tail->next=$first; } echo'<br/>最后留在圈圈的人的编号是'.$tail->no; } addChild($first,$n); showChild($first); //真正来玩游戏 countChild($first); ?> </body> </html>
(2)现在把数2做成变量m
josephu4.php
- <html>
- <head>
- <meta http-equiv=”Content-Type” content=“text/html; charset=gb2312” />
- </head>
- <body>
- <h1>约瑟夫问题解决</h1>
- <?php
- //先构建一个环形链表,链表上的每个节点,表示一个小朋友
- //小孩类
- class Child{
- public no</span><span>; </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="vars">;
- public next=null;
- //构造函数
- public function __construct(no</span><span>){ </span></span></li><li class="alt"><span> <span class="vars">$this</span><span>->no=</span><span class="vars">$no</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">//定义一个指向第一个小朋友的引用</span><span> </span></span></li><li class="alt"><span> <span class="comment">//定义一个空头</span><span> </span></span></li><li class=""><span> <span class="vars">){
- $this->no=$no;
- }
- }
- //定义一个指向第一个小朋友的引用
- //定义一个空头
- first=null;
- n</span><span>=10; </span><span class="comment">//=10; //n表示有几个小朋友
- //写一个函数来创建一个四个小朋友的环形链表
- /*
- addChild函数的作用是:把
n个小孩在构建成一个环形链表, first变量就指向该环形链表的第一个小孩子 - */
- function addChild(&
first</span><span>,</span><spanclass="vars"> ,n){ //此处要加地址符 - //1.头结点不能动 first不能动</span><span> </span></span></li><li class=""><span> <span class="vars">
- cur=first</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">for</span><span>(</span><span class="vars">;
- for(i=0;i</span><span><</span><span class="vars"><n;i</span><span>++){ </span></span></li><li class=""><span> <span class="vars">$child</span><span>=</span><span class="keyword">new</span><span> Child(</span><span class="vars">$i</span><span>+1); </span><span class="comment">//为什么要加1,因为for循环中i是从开始的,但是小朋友的编号是从1开始的</span><span> </span></span></li><li class="alt"><span> <span class="comment">//怎么构成一个环形链表呢</span><span> </span></span></li><li class=""><span> <span class="keyword">if</span><span>(</span><span class="vars">$i</span><span>==0){ </span><span class="comment">//第一个小孩的情况</span><span> </span></span></li><li class="alt"><span> <span class="vars">$first</span><span>=</span><span class="vars">$child</span><span>; </span><span class="comment">//让first指向child,但是还没有构建环形链表</span><span> </span></span></li><li class=""><span> <span class="vars">$first</span><span>->next=</span><span class="vars">$child</span><span>; </span><span class="comment">//自己指向自己</span><span> </span></span></li><li class="alt"><span> <span class="vars">$cur</span><span>=</span><span class="vars">$first</span><span>; </span></span></li><li class=""><span> }<span class="keyword">else</span><span>{ </span></span></li><li class="alt"><span> <span class="vars">$cur</span><span>->next=</span><span class="vars">$child</span><span>; </span></span></li><li class=""><span> <span class="vars">$child</span><span>->next=</span><span class="vars">$first</span><span>; </span></span></li><li class="alt"><span> <span class="comment">//继续指向下一个</span><span> </span></span></li><li class=""><span> <span class="vars">$cur</span><span>=</span><span class="vars">$cur</span><span>->next; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">//遍历所有的小孩,并显示</span><span> </span></span></li><li class="alt"><span> <span class="keyword">function</span><span> showChild(</span><span class="vars">++){
- $child=new Child($i+1); //为什么要加1,因为for循环中i是从开始的,但是小朋友的编号是从1开始的
- //怎么构成一个环形链表呢
- if($i==0){ //第一个小孩的情况
- $first=$child; //让first指向child,但是还没有构建环形链表
- $first->next=$child; //自己指向自己
- $cur=$first;
- }else{
- $cur->next=$child;
- $child->next=$first;
- //继续指向下一个
- $cur=$cur->next;
- }
- }
- }
- //遍历所有的小孩,并显示
- function showChild(first){
- //遍历 cur变量是帮助我们遍历循环列表的,所以不能动
-
cur</span><span>=</span><spanclass="vars"> =first; - while(cur</span><span>->next!=</span><span class="vars">->next!=first){ //cur没有到结尾,就遍历
- //显示
- echo‘<br/>小孩的编号是’.cur</span><span>->no; </span></span></li><li class="alt"><span> <span class="comment">//继续</span><span> </span></span></li><li class=""><span> <span class="vars">->no;
- //继续
- cur=cur</span><span>->next; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">//当退出while循环时,已经到了环形链表的最后,即cur此时指向最后一个小孩,所以还要处里一下最后这个小孩节点</span><span> </span></span></li><li class="alt"><span> <span class="func">echo</span><span class="string">'<br/>小孩的编号是'</span><span>.</span><span class="vars">->next;
- }
- //当退出while循环时,已经到了环形链表的最后,即cur此时指向最后一个小孩,所以还要处里一下最后这个小孩节点
- echo'<br/>小孩的编号是'.cur->no;
- }
- //为了能够删除某个小孩,我们需要一个辅助变量,该变量指向的小孩在
first前面,在 first的前面,因为是环形的,就相当于在队尾了。 - m</span><span>=3; </span></span></li><li class=""><span> <span class="keyword">function</span><span> countChild(</span><span class="vars">=3;
- function countChild(first,m</span><span>){ </span></span></li><li class="alt"><span> <span class="vars">$tail</span><span>=</span><span class="vars">$first</span><span>; </span></span></li><li class=""><span> <span class="keyword">while</span><span>(</span><span class="vars">$tail</span><span>->next!=</span><span class="vars">$first</span><span>){ </span></span></li><li class="alt"><span> <span class="vars">$tail</span><span>=</span><span class="vars">$tail</span><span>->next; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="comment">//当退出while时,我们的$tail就指向了最后这个小孩</span><span> </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="comment">//让$first和$tail向后移动</span><span> </span></span></li><li class=""><span> <span class="comment">//移一下就相当于数了两下,因为还要数自己一下</span><span> </span></span></li><li class="alt"><span> <span class="comment">//如从1号小朋友到2号小朋友,只移动了一下,那么是1号小朋友数1 再数2,因为还数了自己一下。</span><span> </span></span></li><li class=""><span> <span class="comment">//移动2次,相当于数了3下,因为自己数的时候,自己不需要动</span><span> </span></span></li><li class="alt"><span> <span class="comment">//移动m-1次,相当于数了m下 </span><span> </span></span></li><li class=""><span> <span class="keyword">while</span><span>(</span><span class="vars">$tail</span><span>!=</span><span class="vars">$first</span><span>){ </span><span class="comment">//当$tail==$first则说明只有最后一个人了</span><span> </span></span></li><li class="alt"><span> <span class="keyword">for</span><span>(</span><span class="vars">$i</span><span>=0;</span><span class="vars">$i</span><span><</span><span class="vars">$m</span><span>-1;</span><span class="vars">$i</span><span>++){ </span></span></li><li class=""><span> <span class="vars">$tail</span><span>=</span><span class="vars">$tail</span><span>->next; </span></span></li><li class="alt"><span> <span class="vars">$first</span><span>=</span><span class="vars">$first</span><span>->next; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="comment">//把$first指向的节点小孩删除环形链表</span><span> </span></span></li><li class=""><span> <span class="vars">$first</span><span>=</span><span class="vars">$first</span><span>->next; </span></span></li><li class="alt"><span> <span class="vars">$tail</span><span>->next=</span><span class="vars">$first</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="func">echo</span><span class="string">'<br/>最后留在圈圈的人的编号是'</span><span>.</span><span class="vars">$tail</span><span>->no; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> addChild(<span class="vars">){
- $tail=$first;
- while($tail->next!=$first){
- $tail=$tail->next;
- }
- //当退出while时,我们的$tail就指向了最后这个小孩
- //让$first和$tail向后移动
- //移一下就相当于数了两下,因为还要数自己一下
- //如从1号小朋友到2号小朋友,只移动了一下,那么是1号小朋友数1 再数2,因为还数了自己一下。
- //移动2次,相当于数了3下,因为自己数的时候,自己不需要动
- //移动m-1次,相当于数了m下
- while($tail!=$first){ //当$tail==$first则说明只有最后一个人了
- for($i=0;$i<$m-1;$i++){
- $tail=$tail->next;
- $first=$first->next;
- }
- //把$first指向的节点小孩删除环形链表
- $first=$first->next;
- $tail->next=$first;
- }
- echo'<br/>最后留在圈圈的人的编号是'.$tail->no;
- }
- addChild(first,n</span><span>); </span></span></li><li class="alt"><span> showChild(<span class="vars">);
- showChild(first);
- //真正来玩游戏
- countChild(
first</span><span>,</span><spanclass="vars"> ,m); - ?>
- </body>
- </html>
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> </head> <body> <h1>约瑟夫问题解决</h1> <?php //先构建一个环形链表,链表上的每个节点,表示一个小朋友 //小孩类 class Child{ public $no; public $next=null; //构造函数 public function __construct($no){ $this->no=$no; } } //定义一个指向第一个小朋友的引用 //定义一个空头 $first=null; $n=10; //$n表示有几个小朋友 //写一个函数来创建一个四个小朋友的环形链表 /* addChild函数的作用是:把$n个小孩在构建成一个环形链表,$first变量就指向该环形链表的第一个小孩子 */ function addChild(&$first,$n){ //此处要加地址符 //1.头结点不能动 $first不能动 $cur=$first; for($i=0;$i<$n;$i++){ $child=new Child($i+1); //为什么要加1,因为for循环中i是从开始的,但是小朋友的编号是从1开始的 //怎么构成一个环形链表呢 if($i==0){ //第一个小孩的情况 $first=$child; //让first指向child,但是还没有构建环形链表 $first->next=$child; //自己指向自己 $cur=$first; }else{ $cur->next=$child; $child->next=$first; //继续指向下一个 $cur=$cur->next; } } } //遍历所有的小孩,并显示 function showChild($first){ //遍历 cur变量是帮助我们遍历循环列表的,所以不能动 $cur=$first; while($cur->next!=$first){ //cur没有到结尾,就遍历 //显示 echo'<br/>小孩的编号是'.$cur->no; //继续 $cur=$cur->next; } //当退出while循环时,已经到了环形链表的最后,即cur此时指向最后一个小孩,所以还要处里一下最后这个小孩节点 echo'<br/>小孩的编号是'.$cur->no; } //为了能够删除某个小孩,我们需要一个辅助变量,该变量指向的小孩在$first前面,在$first的前面,因为是环形的,就相当于在队尾了。 $m=3; function countChild($first,$m){ $tail=$first; while($tail->next!=$first){ $tail=$tail->next; } //当退出while时,我们的$tail就指向了最后这个小孩 //让$first和$tail向后移动 //移一下就相当于数了两下,因为还要数自己一下 //如从1号小朋友到2号小朋友,只移动了一下,那么是1号小朋友数1 再数2,因为还数了自己一下。 //移动2次,相当于数了3下,因为自己数的时候,自己不需要动 //移动m-1次,相当于数了m下 while($tail!=$first){ //当$tail==$first则说明只有最后一个人了 for($i=0;$i<$m-1;$i++){ $tail=$tail->next; $first=$first->next; } //把$first指向的节点小孩删除环形链表 $first=$first->next; $tail->next=$first; } echo'<br/>最后留在圈圈的人的编号是'.$tail->no; } addChild($first,$n); showChild($first); //真正来玩游戏 countChild($first,$m); ?> </body> </html>
(3)再考虑从第几个人数的问题,变量k;和出列显示
josephu5.php
- <html>
- <head>
- <meta http-equiv=”Content-Type” content=“text/html; charset=gb2312” />
- </head>
- <body>
- <h1>约瑟夫问题解决</h1>
- <?php
- //先构建一个环形链表,链表上的每个节点,表示一个小朋友
- //小孩类
- class Child{
- public no</span><span>; </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="vars">;
- public next=null;
- //构造函数
- public function __construct(no</span><span>){ </span></span></li><li class="alt"><span> <span class="vars">$this</span><span>->no=</span><span class="vars">$no</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">//定义一个指向第一个小朋友的引用</span><span> </span></span></li><li class="alt"><span> <span class="comment">//定义一个空头</span><span> </span></span></li><li class=""><span> <span class="vars">){
- $this->no=$no;
- }
- }
- //定义一个指向第一个小朋友的引用
- //定义一个空头
- first=null;
- n</span><span>=10; </span><span class="comment">//=10; //n表示有几个小朋友
- //写一个函数来创建一个四个小朋友的环形链表
- /*
- addChild函数的作用是:把
n个小孩在构建成一个环形链表, first变量就指向该环形链表的第一个小孩子 - */
- function addChild(&
first</span><span>,</span><spanclass="vars"> ,n){ //此处要加地址符 - //1.头结点不能动 first不能动</span><span> </span></span></li><li class=""><span> <span class="vars">
- cur=first</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">for</span><span>(</span><span class="vars">;
- for(i=0;i</span><span><</span><span class="vars"><n;i</span><span>++){ </span></span></li><li class=""><span> <span class="vars">$child</span><span>=</span><span class="keyword">new</span><span> Child(</span><span class="vars">$i</span><span>+1); </span><span class="comment">//为什么要加1,因为for循环中i是从开始的,但是小朋友的编号是从1开始的</span><span> </span></span></li><li class="alt"><span> <span class="comment">//怎么构成一个环形链表呢</span><span> </span></span></li><li class=""><span> <span class="keyword">if</span><span>(</span><span class="vars">$i</span><span>==0){ </span><span class="comment">//第一个小孩的情况</span><span> </span></span></li><li class="alt"><span> <span class="vars">$first</span><span>=</span><span class="vars">$child</span><span>; </span><span class="comment">//让first指向child,但是还没有构建环形链表</span><span> </span></span></li><li class=""><span> <span class="vars">$first</span><span>->next=</span><span class="vars">$child</span><span>; </span><span class="comment">//自己指向自己</span><span> </span></span></li><li class="alt"><span> <span class="vars">$cur</span><span>=</span><span class="vars">$first</span><span>; </span></span></li><li class=""><span> }<span class="keyword">else</span><span>{ </span></span></li><li class="alt"><span> <span class="vars">$cur</span><span>->next=</span><span class="vars">$child</span><span>; </span></span></li><li class=""><span> <span class="vars">$child</span><span>->next=</span><span class="vars">$first</span><span>; </span></span></li><li class="alt"><span> <span class="comment">//继续指向下一个</span><span> </span></span></li><li class=""><span> <span class="vars">$cur</span><span>=</span><span class="vars">$cur</span><span>->next; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">//遍历所有的小孩,并显示</span><span> </span></span></li><li class="alt"><span> <span class="keyword">function</span><span> showChild(</span><span class="vars">++){
- $child=new Child($i+1); //为什么要加1,因为for循环中i是从开始的,但是小朋友的编号是从1开始的
- //怎么构成一个环形链表呢
- if($i==0){ //第一个小孩的情况
- $first=$child; //让first指向child,但是还没有构建环形链表
- $first->next=$child; //自己指向自己
- $cur=$first;
- }else{
- $cur->next=$child;
- $child->next=$first;
- //继续指向下一个
- $cur=$cur->next;
- }
- }
- }
- //遍历所有的小孩,并显示
- function showChild(first){
- //遍历 cur变量是帮助我们遍历循环列表的,所以不能动
-
cur</span><span>=</span><spanclass="vars"> =first; - while(cur</span><span>->next!=</span><span class="vars">->next!=first){ //cur没有到结尾,就遍历
- //显示
- echo‘<br/>小孩的编号是’.cur</span><span>->no; </span></span></li><li class="alt"><span> <span class="comment">//继续</span><span> </span></span></li><li class=""><span> <span class="vars">->no;
- //继续
- cur=cur</span><span>->next; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">//当退出while循环时,已经到了环形链表的最后,即cur此时指向最后一个小孩,所以还要处里一下最后这个小孩节点</span><span> </span></span></li><li class="alt"><span> <span class="func">echo</span><span class="string">'<br/>小孩的编号是'</span><span>.</span><span class="vars">->next;
- }
- //当退出while循环时,已经到了环形链表的最后,即cur此时指向最后一个小孩,所以还要处里一下最后这个小孩节点
- echo'<br/>小孩的编号是'.cur->no;
- }
- //为了能够删除某个小孩,我们需要一个辅助变量,该变量指向的小孩在
first前面,在 first的前面,因为是环形的,就相当于在队尾了。 - m</span><span>=3; </span></span></li><li class=""><span> <span class="vars">=3;
- k=2;
- function countChild(
first</span><span>,</span><spanclass="vars"> ,m,k</span><span>){ </span></span></li><li class=""><span> <span class="vars">$tail</span><span>=</span><span class="vars">$first</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">while</span><span>(</span><span class="vars">$tail</span><span>->next!=</span><span class="vars">$first</span><span>){ </span></span></li><li class=""><span> <span class="vars">$tail</span><span>=</span><span class="vars">$tail</span><span>->next; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="comment">//考虑是从第几个人开始数的问题,变量k</span><span> </span></span></li><li class=""><span> <span class="comment">//首先要定位</span><span> </span></span></li><li class="alt"><span> <span class="comment">//因为动一下,就相当于数了两下,算上自己了,所以k-1</span><span> </span></span></li><li class=""><span> <span class="keyword">for</span><span>(</span><span class="vars">$i</span><span>=0;</span><span class="vars">$i</span><span><</span><span class="vars">$k</span><span>-1;</span><span class="vars">$i</span><span>++){ </span></span></li><li class="alt"><span> <span class="vars">$tail</span><span>=</span><span class="vars">$tail</span><span>->next; </span></span></li><li class=""><span> <span class="vars">$first</span><span>=</span><span class="vars">$first</span><span>->next; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="comment">//当退出while时,我们的$tail就指向了最后这个小孩</span><span> </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="comment">//让$first和$tail向后移动</span><span> </span></span></li><li class=""><span> <span class="comment">//移一下就相当于数了两下,因为还要数自己一下</span><span> </span></span></li><li class="alt"><span> <span class="comment">//如从1号小朋友到2号小朋友,只移动了一下,那么是1号小朋友数1 再数2,因为还数了自己一下。</span><span> </span></span></li><li class=""><span> <span class="comment">//移动2次,相当于数了3下,因为自己数的时候,自己不需要动</span><span> </span></span></li><li class="alt"><span> <span class="comment">//移动m-1次,相当于数了m下 </span><span> </span></span></li><li class=""><span> <span class="keyword">while</span><span>(</span><span class="vars">$tail</span><span>!=</span><span class="vars">$first</span><span>){ </span><span class="comment">//当$tail==$first则说明只有最后一个人了</span><span> </span></span></li><li class="alt"><span> <span class="keyword">for</span><span>(</span><span class="vars">$i</span><span>=0;</span><span class="vars">$i</span><span><</span><span class="vars">$m</span><span>-1;</span><span class="vars">$i</span><span>++){ </span></span></li><li class=""><span> <span class="vars">$tail</span><span>=</span><span class="vars">$tail</span><span>->next; </span></span></li><li class="alt"><span> <span class="vars">$first</span><span>=</span><span class="vars">$first</span><span>->next; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="comment">//把$first指向的节点小孩删除环形链表</span><span> </span></span></li><li class=""><span> <span class="comment">//出列显示,应该在first没有改变之前先打印输出</span><span> </span></span></li><li class="alt"><span> <span class="func">echo</span><span class="string">'<br/>出圈的人的编号是'</span><span>.</span><span class="vars">$first</span><span>->no; </span></span></li><li class=""><span> <span class="vars">$first</span><span>=</span><span class="vars">$first</span><span>->next; </span></span></li><li class="alt"><span> <span class="vars">$tail</span><span>->next=</span><span class="vars">$first</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="func">echo</span><span class="string">'<br/>最后留在圈圈的人的编号是'</span><span>.</span><span class="vars">$tail</span><span>->no; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> addChild(<span class="vars">){ - $tail=$first;
- while($tail->next!=$first){
- $tail=$tail->next;
- }
- //考虑是从第几个人开始数的问题,变量k
- //首先要定位
- //因为动一下,就相当于数了两下,算上自己了,所以k-1
- for($i=0;$i<$k-1;$i++){
- $tail=$tail->next;
- $first=$first->next;
- }
- //当退出while时,我们的$tail就指向了最后这个小孩
- //让$first和$tail向后移动
- //移一下就相当于数了两下,因为还要数自己一下
- //如从1号小朋友到2号小朋友,只移动了一下,那么是1号小朋友数1 再数2,因为还数了自己一下。
- //移动2次,相当于数了3下,因为自己数的时候,自己不需要动
- //移动m-1次,相当于数了m下
- while($tail!=$first){ //当$tail==$first则说明只有最后一个人了
- for($i=0;$i<$m-1;$i++){
- $tail=$tail->next;
- $first=$first->next;
- }
- //把$first指向的节点小孩删除环形链表
- //出列显示,应该在first没有改变之前先打印输出
- echo'<br/>出圈的人的编号是'.$first->no;
- $first=$first->next;
- $tail->next=$first;
- }
- echo'<br/>最后留在圈圈的人的编号是'.$tail->no;
- }
- addChild(first,n</span><span>); </span></span></li><li class="alt"><span> showChild(<span class="vars">);
- showChild(first);
- //真正来玩游戏
- countChild(
first</span><span>,</span><spanclass="vars"> ,m,$k); - ?>
- </body>
- </html>
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> </head> <body> <h1>约瑟夫问题解决</h1> <?php //先构建一个环形链表,链表上的每个节点,表示一个小朋友 //小孩类 class Child{ public $no; public $next=null; //构造函数 public function __construct($no){ $this->no=$no; } } //定义一个指向第一个小朋友的引用 //定义一个空头 $first=null; $n=10; //$n表示有几个小朋友 //写一个函数来创建一个四个小朋友的环形链表 /* addChild函数的作用是:把$n个小孩在构建成一个环形链表,$first变量就指向该环形链表的第一个小孩子 */ function addChild(&$first,$n){ //此处要加地址符 //1.头结点不能动 $first不能动 $cur=$first; for($i=0;$i<$n;$i++){ $child=new Child($i+1); //为什么要加1,因为for循环中i是从开始的,但是小朋友的编号是从1开始的 //怎么构成一个环形链表呢 if($i==0){ //第一个小孩的情况 $first=$child; //让first指向child,但是还没有构建环形链表 $first->next=$child; //自己指向自己 $cur=$first; }else{ $cur->next=$child; $child->next=$first; //继续指向下一个 $cur=$cur->next; } } } //遍历所有的小孩,并显示 function showChild($first){ //遍历 cur变量是帮助我们遍历循环列表的,所以不能动 $cur=$first; while($cur->next!=$first){ //cur没有到结尾,就遍历 //显示 echo'<br/>小孩的编号是'.$cur->no; //继续 $cur=$cur->next; } //当退出while循环时,已经到了环形链表的最后,即cur此时指向最后一个小孩,所以还要处里一下最后这个小孩节点 echo'<br/>小孩的编号是'.$cur->no; } //为了能够删除某个小孩,我们需要一个辅助变量,该变量指向的小孩在$first前面,在$first的前面,因为是环形的,就相当于在队尾了。 $m=3; $k=2; function countChild($first,$m,$k){ $tail=$first; while($tail->next!=$first){ $tail=$tail->next; } //考虑是从第几个人开始数的问题,变量k //首先要定位 //因为动一下,就相当于数了两下,算上自己了,所以k-1 for($i=0;$i<$k-1;$i++){ $tail=$tail->next; $first=$first->next; } //当退出while时,我们的$tail就指向了最后这个小孩 //让$first和$tail向后移动 //移一下就相当于数了两下,因为还要数自己一下 //如从1号小朋友到2号小朋友,只移动了一下,那么是1号小朋友数1 再数2,因为还数了自己一下。 //移动2次,相当于数了3下,因为自己数的时候,自己不需要动 //移动m-1次,相当于数了m下 while($tail!=$first){ //当$tail==$first则说明只有最后一个人了 for($i=0;$i<$m-1;$i++){ $tail=$tail->next; $first=$first->next; } //把$first指向的节点小孩删除环形链表 //出列显示,应该在first没有改变之前先打印输出 echo'<br/>出圈的人的编号是'.$first->no; $first=$first->next; $tail->next=$first; } echo'<br/>最后留在圈圈的人的编号是'.$tail->no; } addChild($first,$n); showChild($first); //真正来玩游戏 countChild($first,$m,$k); ?> </body> </html>
关键是要在脑海中,有一个内存分布和运行的大致图。
一旦人多了,比如4000个人,从第31个人,数20,这时候就发现程序的力量了,你人工去数,可想而知。
用程序来完成你能完成的事情,但是是快速的完成。
找工作的时候,很容易被考的问题:约瑟夫问题,排序和查找,二叉树的遍历,前序遍历后序遍历,霍夫曼数,最小堆等
有档次的公司都喜欢考算法