PHP算法学习(8) 环形链表 解决约瑟夫问题

2019年2月25日17:29:17

Josephus有过的故事:39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓。于是决定了自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀。然后下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

抽象出的问题是 N个人围成一圈,从第S个人开始报数,报到C的人出圈,从出去的人的下一位,继续从下一任开始重新报数,报到m的人出圈;如此往复,直到所有人出圈。

final class Kid {

    public $no;
    public $next = null;

    public function __construct($no) {
        $this->no = $no;
    }

}
<?php

/*
 * 环形链表 解决约瑟夫问题
 */

final class CircularLinkedList {

    public function addKid($n = 0, &$head = null) {
        for ($i = 0; $i < $n; $i++) {
            $Kid = new Kid($i + 1);
            if ($i == 0) { //第一个小孩的情况
                $head = $Kid; //对象赋值,是引用赋值
                $head->next = $Kid; //自己指向自己
                $current = $head; //对象赋值,是引用赋值
            } else {
                $current->next = $Kid;
                $Kid->next = $head;
//                //继续指向下一个
                $current = $current->next;
            }
        }
    }

    /*
     * $start 从几开始
     * $count 数到几就出圈
     */

    public function play(Kid $head, $start, $count) {
        $current = $head;
        //移动指针从$start 移动到
        while (1) {
            if ($current->no == $start) {
                break;
            }
            $current = $current->next;
        }
//        p($current);
//        pp($this->countKids($current));
//        $all = $this->countKids($current);

        while ($current->next != $current->next->next) {
            //少移动一位,方便一处节点
            for ($i = 1; $i < $count; $i++) {
                $current = $current->next;
            }
            //去除节点
//            p($current);
            p('出去的小孩是  --' . $current->next->no);
            $current->next = $current->next->next;
//            p($current);
            //移动指针,移到删除节点的下一位就是重新数数的那个节点
            $current = $current->next;
        }
        p($current->no);
    }

    public function countKids(Kid $head) {
        $current = $head;
        $count = 1;
        while ($head->no != $current->next->no) {
            $count++;
            $current = $current->next;
        }

        return $count;
    }

}

调用

$CircularLinkedList = new CircularLinkedList();
$CircularLinkedList->addKid(10, $head);
$CircularLinkedList->play($head, 3, 2);

结果

出去的小孩是  --5
出去的小孩是  --8
出去的小孩是  --1
出去的小孩是  --4
出去的小孩是  --9
出去的小孩是  --3
出去的小孩是  --10
出去的小孩是  --7
出去的小孩是  --2
6

 

转载于:https://www.cnblogs.com/zx-admin/p/10432136.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值