關於單向循環鏈表的約瑟夫問題(Java實現)

  • 2020 年 6 月 18 日
  • 筆記

關於單向循環鏈表的約瑟夫問題(Java實現)

最近在學習鏈表時,遇到單向循環鏈表中的約瑟夫問題。在構建循環鏈表的程式碼上,我有一點很不理解,遂記錄下來。

Josephu問題為:

設編號為1, 2.. nn個人圍坐– –圈,約定編號為k (1<=k<=n)的人從1開始報數,數到m的那個人出列,它的下一位又從1開始報數,數到m的那個人又出列,依次類推,直到所有人出列為止,由此產生一個出隊編號的序列。

提示:用一個不帶頭結點的循環鏈表來處理Josephu問題:先構成一個有n個結點的單循環鏈表,然後由k結點起從1開始計數,計到m時,對應結點從鏈表中刪除,然後再從被刪除結點的下一個結點又從1開始計數,直到最後一個結點從鏈表中刪除演算法結束。

 

構建一個單向的環形鏈表思路:
1.先創建第一個節點讓first指向該節點,並形成環形
2.後面當我們每創建- -個新的節點,就把該節點,加入到已有的環形鏈表中即可.
遍歷環形鏈表
1.先讓一個輔助指針(變數)curBoy,指向frt節點
2.然後通過一-個while循環遍歷該環形鏈表即可curBoy.next == first結束

程式碼清單:

package lianbiao;
public class Josepfu {
  public static void main(String[]args){
         CircleSingleLinkedList circleSingleLinkedList =new CircleSingleLinkedList();
         circleSingleLinkedList.addBoy(5);//加入5個小孩節點
         circleSingleLinkedList.showBoy();
         circleSingleLinkedList.countBoy(1, 2, 5);
         }
}
 //創建一個環形的單向鏈表
 class CircleSingleLinkedList{
     // 創建一個first節點當前沒有編號
     private Boy first = null;
     //添加小孩節點,構建成一個環形的鏈表
     public void addBoy(int nums) {
 // nums做一個數據校驗
         if (nums < 1) {
             System.out.println(“nums的值不正確”);
             return;
         }
             Boy curBoy = null; //輔助指針,幫助構建環形鏈表
 //使用for來創建我們的環形鏈表
             for (int i = 1; i <= nums; i++) {
 // 根據編號,創建小孩節點
                 Boy boy = new Boy(i);
 // 如果是第一個小孩
                 if (i == 1) {
                     first = boy;
                     first.setNext(first);//構成環
                     curBoy = first; //讓curBoy指向第一個小孩
                 } else {
                     curBoy.setNext(boy);//
                     boy.setNext(first);//
                     curBoy = boy;
                 }
             }
         }
    
   //遍歷當前的環形鏈表
     public void showBoy() {
     //判斷鏈表是否為空
      if(first== null) {
       System.out.println(“沒有任何小孩~”);
      return;
     }
     //因為first不能動,因此我們仍然使用一個輔助指針完成遍歷
      Boy curBoy = first;
      while (true) {
       System.out.printf(“小孩的編號%d \n”, curBoy.getNo());
       if (curBoy.getNext()==first) {// 說明已經遍歷完畢
        break;
      }
       curBoy = curBoy.getNext(); // curBoy後移
       }
      }
    
     public void countBoy(int startNo, int countNum, int nums) {
      //先對數據進行校驗
      if (first== null || startNo< 1 || startNo> nums) {
       System.out. println(“參數輸入有誤,請 重新輸入”);
       return;
      }
      //創建要給輔助指針,幫助完成小孩出圈
      Boy helper= first;
      //需求創建一個輔助指針(變數) helper ,事先應該指向環形鏈表的最後這個節點
      while (true) {
       if (helper.getNext()==first) { //說明helper 指向最後小孩節點
        break;
       }
       helper = helper.getNext();
      }
      //小孩報數前,先讓first 和helper 移動k- 1次
      for(int j= 0;j < startNo- 1;j++) {
      first = first.getNext();
      helper = helper .getNext();
      }
      //當小孩報數時,讓first 和helper 指針同時的移動m – 1次,然後出圈
      //這裡是一個循環操作,知道圈中只有一個節點
      while(true) {
      if(helper == first) { //說明圈中只有一個節點
       break;
      }
       //讓first 和helper 指針同時的移動countNum- 1
       for(int j = 0;j < countNum- 1;j++) {
        first = first. getNext();
        helper = helper.getNext();
       }
       //這時first 指向的節點,就是要出圈的小孩節點
       System.out.printf(“小孩%d出圈\n”, first.getNo());
       //這時將first指向的小孩節點出圈
       first = first.getNext();
       helper .setNext(first); //
       }
       System.out. printf(“最後留在圈中的小孩編號%d \n”, first. getNo());
       }
      }
  class Boy {
     //創建一個Boy類,表示-一個節點
     private int no;//編號
     private Boy next;//指向下一個節點,默認null
     public Boy(int no) {
         this.no = no;
     }
     public int getNo() {
         return no;
     }
     public void setNo(int no) {
         this.no = no;
     }
     public Boy getNext() {
         return next;
     }
     public void setNext(Boy next) {
         this.next = next;
     }
  }
 問題描述:
在addboy()方法中