约瑟夫问题(单向循环链表经典例题)

1. 约瑟夫问题的简介及实现思路

  • Josephu(约瑟夫、约瑟夫环)问题:

    设编号1,2,…,n 的 n 个人围坐一圈,约定编号为 k (1 <= k <= n)的人从 1 开始报数,数到 m 的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。

  • 大致实现思路:

    1. 将所有人添加到循环链表中
    2. 然后由k结点起从1开始计数,计到 m 时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除,算法结束
  • 实现图解:

    约瑟夫问题(单向循环链表经典例题)_第1张图片

  • 单向循环链表的实现:

    请见上篇博客

  • 玩家类的实现:

    public class GamePlayer {
        private String name;
        private int age;
    
        public GamePlayer(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "GamePlayer{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }

2. 约瑟夫问题的代码实现:

import java.util.Scanner;

public class Josephus {
    public static void main(String[] args) {
        //循环链表
        CircularLinkedList list = new CircularLinkedList();

        //先来十个玩游戏的人
        GamePlayer player1 = new GamePlayer("玩家一", 10);
        GamePlayer player2 = new GamePlayer("玩家二", 11);
        GamePlayer player3 = new GamePlayer("玩家三", 12);
        GamePlayer player4 = new GamePlayer("玩家四", 13);
        GamePlayer player5 = new GamePlayer("玩家五", 14);
        GamePlayer player6 = new GamePlayer("玩家六", 15);
        GamePlayer player7 = new GamePlayer("玩家七", 16);
        GamePlayer player8 = new GamePlayer("玩家八", 17);
        GamePlayer player9 = new GamePlayer("玩家九", 18);
        GamePlayer player10 = new GamePlayer("玩家十", 19);

        //把这十个人存到结点里,并加入到链表里
        CircularNode node0 = new CircularNode(player1);
        list.add(node0);
        CircularNode node1 = new CircularNode(player2);
        list.add(node1);
        CircularNode node2 = new CircularNode(player3);
        list.add(node2);
        CircularNode node3 = new CircularNode(player4);
        list.add(node3);
        CircularNode node4 = new CircularNode(player5);
        list.add(node4);
        CircularNode node5 = new CircularNode(player6);
        list.add(node5);
        CircularNode node6 = new CircularNode(player7);
        list.add(node6);
        CircularNode node7 = new CircularNode(player8);
        list.add(node7);
        CircularNode node8 = new CircularNode(player9);
        list.add(node8);
        CircularNode node9 = new CircularNode(player10);
        list.add(node9);

        Scanner sc = new Scanner(System.in);
        System.out.println("请输入从第几个人开始游戏...(1-10)");
        int k = sc.nextInt();
        System.out.println("请输入报数的数字...");
        int m = sc.nextInt();
        //模拟一个计数器
        int count = 1;
        //如果圈内还有两个人及两个人以上,那么游戏继续
        while (list.getSize()!=1){
            //首先求出要出列的人对应的索引
            int index = (m+k-2)%list.getSize();
            //根据索引拿到该索引对应的玩家信息
            GamePlayer player = (GamePlayer) list.getByIndex(index).data;
            //根据索引删掉此索引对应的玩家,表明他已出列
            list.delByIndex(index);
            System.out.println("第"+(count++)+"个玩家已出列,他是:"+player);
            //修改 k 的值,下次从已出列的下一个人开始计数
            k = index+1;
        }
        //求出最后一个出列的玩家
        GamePlayer lastPlayer = (GamePlayer) list.getByIndex(0).data;
        //删除最后一个玩家,表示他也已经出列
        list.delByIndex(0);
        System.out.println("第10个玩家已出列,他是:"+lastPlayer);

    }
}

3. 结果展示:

约瑟夫问题(单向循环链表经典例题)_第2张图片

你可能感兴趣的:(Java-数据结构与算法)