一、第一种方式,将表list看为元素固定的对象,即只修改元素的值而不改变表的结构——不加入或删除表元素。
相当于摆了一圈n把椅子,人可以走但椅子在那里且位置不变。没有人时用0来
初始
- 建立一个包含n个人的表
- 找到第k个人,从那里开始
处理过程中采用把相应的表元素修改为0的方式来表示出列,反复做
- 数m个(尚在坐着)人,遇到表的末端就转回到表的下标0(即表头处)继续
- 把表示第m个人的表元素修改为0
n个人出列即结束
def Josephus(n, k, m):
people = list(range(1, n+1))
i =k -1
for num in range(n): #每循环一次,一个人出列(设为0)
count = 0
while count < m:
if people[i] > 0: #第i人未出列时,报“1”,计数器加一
count += 1
if count == m: #计数器加到m(数到第m个人时)
print(people[i], end="")
people[i] = 0
i = (i+1) % n #i自加一,直到超过人数n时,重置
if num < n-1:
print(", ",end="")
else:
print("")
return
二、采用出列的方式排,每出列一次,表长度减1
- 采用列表的拆分合并来进行,每出列一个人,其后面一人变成了表头元素
- 将重置的表头与出列人前面的表元素重组合并成一个新列表
- 对新列表重复进行出列处理,注意表
def Josephus_A(n, k, m):
L = [i for i in range(1,n+1)]
flag = [] #记录出列人序号
count = 0
while len(L) is not 1:
L1 = L[k:] #以第k个人为起始点,对人数list进行重排
L2 = L[:k]
L = L1+L2
if count == 0:
k = m - 2 #对起始点人单独处理(下标从0开始)
count = 1
else:
k = m - 1
if len(L) < m: #当人数列表list中人数小于报数间隔时,取余再进行
flag.append(L.pop((m % len(L)) - 1))
else:
flag.append(L.pop(k))
flag.append(L.pop(0)) #将最后一个元素添加到表尾
return flag
三、对于二的改进型做法
def Josephus_B(n, k, m):
people = list(range(1, n+1))
num, i = n, k-1
for num in range(n, 0, -1):
i = (i + m-1) % num
print(people.pop(i),end=(", " if num > 1 else "\n"))
return
四、采用循环单链表方式
实现的方式类似于二,只是二中需要手动对表单进行合并生成新表,循环链表也是将此过程看作是结点的转动过程。只需要对链表的next域进行设置即可。
- 循环单链表
class LinkedListUnderflow(ValueError):
pass
class LNode:
def __init__(self, elem, next_=None):
self.elem = elem
self.next = next_
#循环单链表
class LCList:
def __init__(self):
self._rear = None
def is_empty(self):
return self._rear is None
def prepend(self, elem):
p = LNode(elem) #要进行插入的前端结点
if self._rear is None: #由于是循环链表,如果尾结点为空,表明这个表是空表
p.next = p
self._rear = p
else:
p.next = self._rear.next
self._rear.next = p
def append(self, elem):
self.prepend(elem)
self._rear = self._rear.next
def pop(self):
if self._rear is None:
raise LinkedListUnderflow("in pop of CLList")
elif self._rear.next is self._rear:
p = self._rear.next.elem
self._rear = None
return p
else:
p = self._rear.next.elem
self._rear.next = self._rear.next.next
return p
def printall(self):
if self.is_empty():
return
p = self._rear.next
while True:
yield p.elem
if p is self._rear:
break
p = p.next
- Josephus函数
class Josephus(LCList):
def turn(self, m):
for i in range(m):
self._rear = self._rear.next
def __init__(self, n, k, m):
super().__init__()
for i in range(n):
self.append(i+1)
self.turn(k-1)
while not self.is_empty(): #若当前的链表非空,则进行结点的删除
self.turn(m-1)
print(self.pop(),end=("\n" if self.is_empty() else ", "))
- 图解