[学习笔记]Josephus问题

本文探讨了Josephus问题的四种解决方法。首先,通过仅修改元素值来保持列表结构不变,模拟人们围绕椅子的场景。其次,通过出列方式处理,每次出列后减少列表长度。接着,对第二种方法进行了改进。最后,使用循环单链表的方法解决,通过调整链表节点实现问题求解。
摘要由CSDN通过智能技术生成
一、第一种方式,将表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 ", "))
  • 图解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值