不带头结点的单向循环链表的示意图
循环链表的应用场景【约瑟夫问题】
现假设 n = 5(一共有 5 个人),k = 1(从第 1 个人开始报数), m = 2(数 2 下),则出队编号的序列为:2 -> 4 -> 1 -> 5 -> 3
创建单向循环链表
代码实现:
# 创建一个 Node 类,表示一个节点
class Node:
next = None # 指向下一个节点
def __init__(self, no: int):
self.no = no
# 创建一个单向循环链表
class SingleCircleLinkedList:
first = None # 指向循环链表的第一个节点,初始为空
def add(self, node: Node):
if not self.first:
# 如果添加的是第一个节点
self.first = node
node.next = self.first
else:
temp = self.first
while temp.next != self.first:
temp = temp.next
# 找到了循环链表的最后一个节点
temp.next = node
node.next = self.first
# 遍历循环链表
def for_single_circle_linked_list(self):
# 判断链表是否为空
if not self.first:
print("链表为空...")
return
temp = self.first
while True:
end = " -> " if temp.next != self.first else ""
print(temp.no, end=end)
temp = temp.next
if temp == self.first:
break
print()
# num 为环形链表的节点个数
def test_single_circle_linked_list(num):
scll = SingleCircleLinkedList()
for i in range(num):
scll.add(Node(i + 1))
scll.for_single_circle_linked_list()
test_single_circle_linked_list(5)
约瑟夫问题思路分析及代码实现
约瑟夫问题的代码实现
# 约瑟夫问题的代码实现
# 根据用户输入,计算节点出圈顺序
def josepfu(n: int, m: int, k: int):
"""
现假设 n = 5(一共有 5 个人)
k = 1(从第 1 个人开始报数)
m = 2(数 2 下)
则出队编号的序列为:2 -> 4 -> 1 -> 5 -> 3
"""
# 校验数据
if k < 1 or k > n:
print("输入有误!")
return
# 1、创建循环链表
s = SingleCircleLinkedList()
# 2、向循环链表中添加 n 个节点
for i in range(n):
s.add(Node(i + 1))
# 3、找到要开始报数的节点的前一个节点
pre = None
temp = s.first
while True:
if temp.next.no == k:
# nonlocal pre
pre = temp
break
temp = temp.next
# 4、first 指向要报数的节点, pre 指向要报数的前一个节点
first = pre.next
print("出圈顺序为:")
while first != pre:
# 5、让 first 报数 m 次,即让 first 和 pre 移动 m - 1 次
for i in range(m - 1):
pre = pre.next
first = first.next
# 6、当 first 指向的节点出圈
print(first, end=" -> ")
first = first.next
pre.next = first
print(first)
josepfu(5, 2, 1)
josepfu(125, 20, 10)