约瑟夫问题的python实现

约瑟夫问题

约瑟夫问题,简而言之,即N个人围成一圈,从第一个开始报数,第M个出局,然后下一个人重新报数。
例如N=6,M=5:
初始座位:1、2、3、4、5、6
第一轮:从左往右数,5出局,序列重置为:1、2、3、4、6;
第二轮:从6开始数,4出局,序列重置为:1、2、3、6;
第三轮:从6开始数,6出局,序列重置为:1、2、3;
.....
如此循环直到最后一个,则:
出局的顺序是:5,4,6,2,3,1。
 

约瑟夫问题的实现
约瑟夫问题的实现,即通过程序产生约瑟夫序列,本文将通过下面两种方式实现:

  1. python中的list(伪数组)结构实现;
  2. python的链结构实现;

python的list(伪数组)结构实现

采用list来实现,暂且理解为数组,由于每一轮都有call到的位置要出局,下一轮的报数里不会有出局者。
因此有两种考虑:

  1. 通过在list中删除(remove)每一轮的出局者,区别于C语言的数组的是,python中的list在调用remove()方法后,删除的位置后面的索引值也会向前缩减;
  2. 通过给初始的list中的每一个值添加flag(True or False),出局的赋值为False,只有当Flag值为True的才进行报数操作

在这里,我们使用第2种方式来实现
主要逻辑上:
通过使用while造成list的循环圈,通过num作为报数指标,从而不受到list坐标的影响,而只被每次报数成功时影响到值(如果
要以list坐标作为参考,就会受到前面几轮已经出局的位置的影响).比如,当一开始进行到call=5时,第五个被置为False,此时
num=1,而for循环未结束,因此第6个是报1,而6号(也就是list的最后一位)报完数后,num=2,此时for循环结束,但while循环
又导致他们继续for循环,从1号开始检查是否应该报数,而num值仍是接着list的上一个循环结束时报到的数进行下去。
在判断循环何时结束的条件上:
使用python内置函数any(),当所有玩家都出局的时候,那么list中每一位的值都将被置为False,而any()函数是只要有一真值就返回真。  

# -*- coding: utf-8 -*-
"""
Created on Thu Sep 27 12:04:57 2018
Description:约瑟夫问题的列表实现,基于python
Version:1.0    
@author: HJY
"""
#控制参数:
nums = 41
call = 3
#参数定义:
peoples = []
for _ in range(nums):
    peoples.append(True)

result = []
num =1

while(any(peoples)):
    for index,people in enumerate(peoples):
        if people:
            if num == call:
                peoples[index] = False
                result.append(index+1)
#                print(index+1)#每轮的出局者                
#                print(peoples)#每次的队列状态
                num = 1               
            else:
                num += 1

print('-'* 25)
print('\n总数为%d,报数为%d' % (nums,call))        
print('约瑟夫序列为:\n%s\n' % result)      
print('-'* 25)

python的链结构实现

根据约瑟夫序列构造链,其实不用这么复杂,只是笔者当时也顺便写了链的方法,一般来说,实现约瑟夫的功能只需要下面这个类的"__init__"函数即可,只用这个函数也可以构造链。

# -*- coding: utf-8 -*-
"""
Created on Sun Sep 30 10:10:09 2018

Description:约瑟夫问题的链表实现,基于python3.x
Version:v1.0
    
@author: HJY
"""

#构建链节点结构
class Node():
    
    def __init__(self,Node=None,index = None):
        self.data = index
        self.flag = 1
        self.next = Node
       
    def __str__(self):
        return 'node-' + str(self.data)
    
    def link_print(self):
        #循环链表打印 
        p = self
        links = ''
        flags = ''
        while 1:   
            links += '-->' + str(p.data)
            flags += '-->' + str(p.flag)
            p = p.next
            if p == self:            
                break
        print(links)
        print(flags)
        print('#'*20)
        
             
    def create_clink(self,nodes,nextNode_create = 0):
        '''该函数用于创建循环列表,nodes为创建的节点数(包括头结点),nextNode_create
参数为后续扩展用,主要用于避免调用的节点本身就已经在链中或循环链的情况,暂时
没有补充该功能。'''
        #如果调用该函数的节点存在在一链上,那么拒绝调用,或者访问下一节点
        if self.next != None and nextNode_create == 0:     
            return
        else:
            p = self
            for i in range(nodes-1):
                p.next = Node(index = self.data + i + 1)
                p = p.next
            p.next = h
        
    def delete_node_incLink(self,header):
        '''删除调用者自身,并返回其上一个节点的指针,其中header参数为链表初始的指针'''
        #寻找待删除节点的前一个节点
        p = header
        while 1:
            if p.next == self:
                break
            else:
                p = p.next
        
        p.next = self.next
        return p

同样的有两种方案:

  1. 链表以节点值的方式标识是否已出局
  2. 链表直接以删除操作将每一轮的call出局

方案一的代码实现:

#---------------------方案1--------------------------
#1、链表以节点值的方式标识是否已出局
#---------------------------------------------------
def solveby1(header,nums,call):
    p = header
    cursor = 1
    out = 0
    while out<nums:  
        if cursor == call:
            p.flag = 0
            out +=1
            print(p)
    #        Node.link_print()#该语句可以查看每一轮的运作情况
            cursor = 0   
        p = p.next    
        if p.flag:
            cursor +=1
            

方案2的代码实现:

扫描二维码关注公众号,回复: 4816283 查看本文章

此处需要修改,暂不提供

主调用代码:

if __name__ == '__main__':
    nums = 41#参与者总数
    call = 3#报数
    h = Node(index = 1)#头结点
    h.create_clink(nodes=nums)  
    #链表打印 
    h.link_print()
    solveby1(h,nums,call)
#    print('*'*10+'方案2'+ '*'*10)
#    solveby2(h,nums,call)

猜你喜欢

转载自blog.csdn.net/yeshankuangrenaaaaa/article/details/83024537
今日推荐