1. 程式人生 > 程式設計 >使用python從三個角度解決josephus問題的方法

使用python從三個角度解決josephus問題的方法

0 寫在前面

josephus問題是資料結構教材中的一個常見例項,其問題可以描述為:

設nnn個人圍坐一圈,現在要求從第kkk個人開始報數,報到第mmm個的人退出。然後從下一個人開始繼續按照同樣規則報數並退出,直到所有人退出為止。要求按照順序輸出每個人的序列號。

1 基於陣列概念的解法

首先考慮基於python的list和固定大小的陣列概念,即將list看作元素個數固定的物件,只改變值而不刪除元素,相當於擺了一圈nnn把椅子,人雖然退出但是椅子還在,我們可以給每個人從111到nnn編號,沒有人的位置用000表示,思路如下:

初始

  • 建立包含nnn個人(編號)的list
  • 找到第kkk個人開始

執行

  • 從kkk的位置開始數到mmm,中間遇到000的就跳過
  • 數到mmm之後,將其值改為000
  • 然後繼續迴圈,總共迴圈nnn次(因為每次迴圈就會退出一個人)

程式碼如下:

def josephus_A(n,k,m):
  people = list(range(1,(n+1)))
  i = k-1
  for num in range(n):
    count = 0
    while count < m: 
      if people[i] > 0:
        count += 1
      if count == m:
        print(people[i],end=" ")
        people[i] = 0
      i = (i+1) % n # count只是flag,真正記的數是i
    if num < n-1:
      print(end=",",)
    else:
      print(" ")

2 基於順序表的解法

順序表是線性表的一種,即表中元素放在一塊足夠大的連續儲存區裡,首元素存入儲存區開始位置,其餘元素依次存放。順序表在python中的也是list,跟第一種解法不同,當第mmm個人退出需要進行刪除元素的操作,才是順序表。而第一種解法的陣列想要刪除並不是那麼容易,這裡是因為python中沒有內建對陣列的支援,所以用list代替,具體可以參照c++中的陣列,如果要刪除中間的某個元素的話,必須對後面的元素重新編號。程式碼實現如下:

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

3 基於迴圈單鏈表的解法

單鏈表即單向連結表,典型的就是c++中的連結串列,迴圈單鏈表就是頭尾相連的單鏈表,也是線性表的一種,這道題目使用迴圈單鏈表記錄nnn個人圍坐一圈最為契合。我們只需要數到第mmm個結點就刪除,刪除操作對於連結串列來說比較容易,而且不需要有i = (i+1) % n這樣的整除操作。但是問題在於python並沒有像c++那樣有內建對連結串列的支援,因此需要建立一個連結串列的類,建立是比較麻煩的,但是操作比較簡單,如下:

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")
    p = self._rear.next
    if self._rear is p:
      self._rear =None
    else:
      self._rear.next=p.next
    return p.elem
  def printall(self): # 輸出表元素
    if self.is_empty():
      return
    p = self._rear.next
    while True:
      print(p.elem)
      if p is self._rear:
        break
      p=p.next
class LinkedListUnderflow(ValueError): # 自定義異常
  pass
class Josephus(LCList):
  def __init__(self,n,m):
    LCList.__init__(self)
    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 ","))
  def turn(self,m):
    for i in range(m):
      self._rear = self._rear.next

到此這篇關於使用python從三個角度解決josephus問題的方法的文章就介紹到這了,更多相關python josephus問題內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!