约瑟夫问题是个有名的问题:N个小孩围成一圈,从第一个开始报数,第M个将出局,然后从出局的那个孩子的下一个重新开始报数,每个人依次出局。 例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3,1。
具体实现思路如下:
建立一个没有头结点的单向循环链表,用于存放所有小孩。
因为每次出局一个人后,下一个人要重新从1开始报数。所以设置一个指针专门指向第一个报数的人。
因为每次没轮到报M的小孩,每个小孩报的数就会递增,所以用while循环<m-1作为条件,结束这个循环就一位着一个小孩要出局。
出局就是删除结点的操作。
具体代码如下:
#约瑟夫问题
#约瑟夫问题是个有名的问题:N个小孩围成一圈,从第一个开始报数,第M个将出局,然后从出局的那个孩子的下一个重新开始报数
# 例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3,1.
#要用不带头结点的循环链表存放所有人
class Child:#结点类型
def __init__(self.nol):
self.no=nol
self.next=None
class Joseph:
def __init__(self,n1,m1):
self.n=n1
self.m=m1
self.first=Child(1)#设置第一个结点
t=self.first#t始终指向头结点,便于最后形成环,便于引用标记
for i in range(2,self.n+1):
p=Child(i)
t.next=p
t=p#指针移动到下一位
t.next=self.first#最后一个结点的next域指向头结点,形成环
#出局就代表这个结点被删除,然后重新开始报数
def Jsequence(self):
for i in range(1,self.n+1):#最终,所有人都将出局,也就是每次循环都将出局一人
p=self.first#设置一个指针,标志每次循环开始的位置,并且每次循环结束删除一个结点之后都要重置first结点
j=1#j用来判断报数出局的那个人
while j<self.m-1:#j<self.m-1表示话没有轮到那个人,j就要+1,并且指针也要后移一位
j+=1
p=p.next
#退出循环表示下一个就是要退出的那个人
q=p.next#标记要退出的那个人
print(q.no,end='')#输出要退出的那个人
p.next=q.next#单链表的删除操作
self.first=p.next#重置first,再进行下一次循环
print()
n=6
m=3
L=Joseph(n.m)
print("n=%d,m=%d的约瑟夫序列"%(n,m))
L.Jsequence()
具体代码执行图解如下: