介紹
和單向鏈表的惟一區別就是,在鏈表最後的節點指向了鏈表的頭節點.
案例:
單向環形鏈表經典的案例就是約瑟夫環的問題,引伸出來相似猴子選大王,丟手帕等都是約瑟夫的實際場景.
假設有編號爲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;
}
}
}
- 新建兩個變量$temp和$helper,現將$temp指向$first,$helper指向鏈表的最後一我的.
- 將$temp和$helper都移動k-1位,找到開始報數的那我的.
- 當$temp開始報數時,$temp和$helper同時移動$num位.
- 最後將$helper的next域指向$temp的next,$temp向後移動一位,即完成出列.
- 循環第二步,直到$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;
}