数据结构 | Josephus问题

Josephus问题

约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列,类似于丢手绢。

 

1.基于“数组”概念的解法

选择什么数据结构?为什么用数组?

基本思想:人推出了,但是保留其位置,将其位置标记为0,这样做的好处就是,保留了整个表的结构是不变的,处理起来很方便,代码简洁易懂

算法思路
  • 通过数组,将N个人看成数组元素;
  • 出局时元素设为0
  • 循环报数时只将数组元素为1的元素计数
def josephus_A(n,k,m):
    People = list(range(1,n+1))                                 # 生成列表[1,2,...,n]
    i=k-1                                                       # 从第k位同学开始,其索引为k-1
    for num in range(n):
        count = 0
        while count < m:
            if People[i]>0:                                     # 此位置的同学还未推出
                count += 1
            if count == m:                                      # 报数到m该同学推出
                print(People[i],end="," if num<n-1 else "\n")
                People[i] =0                                    # 标记
            i = (i+1) % n                                       # i+1使之指向下一位同学;并且取模,当i>n循环完了一圈,从头新一轮

    return

josephus_A(10,5,6)

'''
10 6 3 1 9 2 5 4 8 7 
'''
分析:
  • 首先,既然是n个人,那么首先定义一个列表,里面元素是[1,2,3,4,...n],指定第k个人,他的下标就是k-1;

  • 然后,既然是将n个人都找出来,每次必定会出来一个人,所以我们的for循环是n次;

  • 在每找一个人的过程中又是经过m个人,所以,用while循环代替for循环,指定初始的count=0,所以while循环的总次数count不能超过m次,每一轮找到一个正常人(非0)就count加1,直到count==m,将这个位置的人赋值为0,不再参与下一轮游戏;

  • while循环里面,每结束一轮循环判断完一个人之后,就需要指向下一个同学即i=i+1,使列表的索引指向下一位同学。但是因为是个圆环,列表只有n个元素,所以赋值的同时取模做运算。分2种情况

    • 当i+1小于n的时候,i就赋值为i+1,也就是下一个同学;

    • i>n时循环完了一圈,从头新一轮的筛选;

 

2.基于顺序表的解

   把保存人员编号的list按表的方式处理,一旦确定了应该退出的人,就将表示其编号的元素从表中删除。这样随着计算的进行,所用的表将变的越来越短。用num表示表的长度,每退出一个人表的长度num就减一,直至表的长度为0时结束。采用这种想法和设计,表中的元素全是有效元素(不再出现表示没人的0),元素计数与下标计数得到统一,所以,下标更新可以用i=(i+m-1)%num统一表示。

def josephus_L(n,k,m):
    people = list(range(1,n+1))

    i = k-1
    for num in range(n,0,-1):
        i = (i+m-1)%num
        print(people.pop(i),end=" " if num>1 else "\n")

josephus_L(10,5,6)

注意:else后面不需要写end="\n"

 

3.基于循环单链表的解     

class Josephus(LCList):
    def turn(self,n):
        for i in range(n):
            self._rear = self._rear.next

    def __init__(self,n,k,m):
        LCList.__init__(self)

        for i in range(n):
            self.append(i+1)

        self.turn(k-1)
        for i in range(n):
            self.turn(m-1)
            print(self.pop(),end=", " if i != n-1 else "\n")

Josephus(10,5,6)

 

 

                                                                                                         

posted @ 2020-03-17 14:26  PythonGirl  阅读(764)  评论(0)    收藏  举报