← 返回内容列表

循环链表与约瑟夫环:一个古老问题的现代解法

分享本文
循环链表与约瑟夫环:一个古老问题的现代解法

公元 1 世纪的犹太历史学家约瑟夫斯留下一道生死题:n 个人围成一圈,每数到 m 就出圈,最后谁活下来?今天用循环链表,把这道两千年前的题讲成一行优雅的代码。

约瑟夫环的故事:罗马军队被围,n 名将士决定宁死不降,围成一圈,从某人起每数到第 m 人就杀掉,直到最后一人自尽。约瑟夫斯算出自己该站哪才活下来——这道题从此以他的名字命名。

为什么用循环链表?人"围成一圈"这个设定,天然就是循环链表:尾节点的 next 指回头节点。每数 m 下,就沿 next 走 m-1 步,然后删除当前节点(双向或单链都可 O(1) 摘除已知节点),被删节点的后继成为新的当前点,继续数,直到链上只剩一个节点。

代码骨架(单循环链表):

build circle of n nodes    repeat: advance m1 steps, delete current    until 1 left\text{build circle of } n \text{ nodes} \;\Rightarrow\; \text{repeat: advance } m-1 \text{ steps, delete current} \;\Rightarrow\; \text{until } 1 \text{ left}

这题的妙处在于:它既是历史趣闻,又是检验"链表删除 + 循环终止"基本功的绝佳练习。更进阶的版本可以用数学递推直接算出幸存者位置(O(n) 而非模拟),但理解循环链表的模拟,是迈出第一步的关键。

今天我们从 C3 节点把循环链表讲透,约瑟夫环就是它最富戏剧性的"用户案例"。

约瑟夫环:循环链表12345678尾节点 next 回头节点 → 围成一圈,每数 m 删一个

图:n 人围成一圈,循环链表天然建模

参考代码(Python)

人围成一圈天然是循环链表,下面用循环链表模拟约瑟夫环。

class Node:
    def __init__(self, v): self.v=v; self.next=None

def josephus(n, m):
    head=Node(1); cur=head
    for i in range(2, n+1):
        cur.next=Node(i); cur=cur.next
    cur.next=head            # 尾连头 → 循环链表
    while cur.next != cur:   # 剩一个时停止
        for _ in range(m-1): cur=cur.next
        cur.next=cur.next.next   # 删除下一节点
    return cur.v

关联推荐

评论 (0)

正文划词可点「问萝卜特」——自动发评论并由 AI 回复

加载评论中…