数据结构之单向环形链表

介绍

和单向链表的唯一区别就是,在链表最后的节点指向了链表的头节点.

数据结构之单向环形链表_第1张图片

案例:

单向环形链表经典的案例就是约瑟夫环的问题,引申出来类似猴子选大王,丢手帕等都是约瑟夫的实际场景.
假设有编号为1,2,3...n的人围成一圈,约定编号为k(1 <= k <= n)的人开始报数,数到m的那个人出列,他的下一位又从1开始报数,数到m的那个人在出列,以此类推,直到所有人出列完毕,由此产生出一个出队的编号序列.
  • 构建节点类,每个节点代表一个人,节点包含编号和next域
class Node
{
    public $no;
    public $next;

    public function __construct($no)
    {
        $this->no = $no;
    }
}
  • 创建一单向环形链表的类
class CircleLinkedList
{
    public $first;
}
  • 生成一个长度为total的单向环形链表,这里需要两个变量$first和$cur,$first指向链表的头节点,$cur指向当前链表的最后一个节点.
public function addNode($total)
{
    $cur = null;
    //循环插入$total个节点
    for ($i = 1; $i <= $total; $i++) {
        $boy = new Node($i);
        if ($i == 1) {
        //如果是第一个节点,则将$first指向它.
            $this->first = $boy;
            $cur = $boy;
        } else {
        //新的人的next域指向第一人,形成一个环状.
            $boy->next = $this->first;
            //将$cur后移之下新的人
            $cur->next = $boy;
            $cur = $boy;
        }
    }
}
  • 出圈思路:
  1. 新建两个变量$temp和$helper,现将$temp指向$first,$helper指向链表的最后一个人.
  2. 将$temp和$helper都移动k-1位,找到开始报数的那个人.
  3. 当$temp开始报数时,$temp和$helper同时移动$num位.
  4. 最后将$helper的next域指向$temp的next,$temp向后移动一位,即完成出列.
  5. 循环第二步,直到$temp == $helper说明链表只剩下一个人,出列完毕.
public function leaveCircle($k, $num)
{
    //现将$temp指向$first
    $temp = $this->first;
    //然后通过遍历将$temp指向链表的最后一个人.
    while (true) {
        if ($temp->next == $this->first) {
            break;
        }
        $temp = $temp->next;
    }
    //$temp和$helper移动k-1位找到开始报数的那个人
    for ($i = 0; $i < $k - 1; $i++) {
        $this->first = $this->first->next;
        $temp = $temp->next;
    }
    //循环遍历出列
    while (true) {
        //如果$first == $temp说明链表只剩下一个节点,退出循环
        if ($this->first == $temp) {
            break;
        }
        //开始报数,$temp和$helper开始移动
        for ($i = 0; $i < $num - 1; $i++) {
            $this->first = $this->first->next;
            $temp = $temp->next;
        }
        //$this->frist指向报数结束后的那个人
        echo "\n" . "编号为" . $this->first->no . "的人出圈";
        //将当前指针$frist移动到下一个,然后让$temp的next指向$first,完成出圈
        $this->first = $this->first->next;
        $temp->next = $this->first;

    }
    echo "\n" . "最后一个人的编号为:" . $this->first->no;
}

你可能感兴趣的:(php,数据结构和算法)