单向环形链表的应用--约瑟夫问题

约瑟夫问题:丢手帕游戏是约瑟夫问题的一个变种,游戏很简单,n个人围成一个圈,标号为1到n,约定编号为k(1<=k<=n)的人从1开始报数,报到第m个的人出列,然后下一个人继续从1开始报数,数到第m的那个人出列,如此循环,直到所有人出列,由此产生一个出队编号的序列。

这里有三个主要的因素:
1、多少个人
2、从多少号开始 
3、报到第多少号出列

如果是5个人、从1开始、数到2出列

如果要解决 这个问题:

1、构建一个单向环形链表
①先创建第一个节点,让head指向该节点并形成一个环形
②每创建一个新的节点,就把该节点加入到已有的环形链表中

2、遍历环形链表
①先让一个辅助指针cur指向head节点
②通过while循环遍历即可 cur.next = head 遍历完毕

3、根据用户输入,生成出圈顺序
①需要创建一个辅助指针tmp指向环形列表最后一个节点
②报数前,先让first和tmp移动k-1次
②当报数时,让head和tmp同时移动m-1次
③将head指向的节点出圈 first = first.next
                                         tmp.next = head

public class Josepfu {
    public static void main(String[] args) {
        CircleSingleList circleSingleList = new CircleSingleList();
        circleSingleList.addNode(5);
        //  circleSingleList.disPlay();
        circleSingleList.countNode(1,2,5);
    }
}

//创建节点
class Node {
    public int no;
    public Node next;
    public Node(int no) {
        this.no = no;
    }
}

//创建一个环形链表
class CircleSingleList {
    Node head;
    public CircleSingleList() {
        this.head = head;
    }

    //添加环形单链表节点
    public void addNode(int nums) {
        if (nums < 1) {
            return;
        }
        Node cur = null;
        for (int i = 1; i <= nums; i++) {
            Node node = new Node(i);
            if (i == 1) {
                //自成环
                this.head = node;
                this.head.next = this.head;
                cur = this.head;
            } else {
                cur.next = node;
                node.next = head;
                cur = node;
            }
        }
    }

    //遍历显示
    public void disPlay() {
        if (this.head == null) {
            return;
        }
        Node cur = this.head;
        while (true) {
            System.out.print(cur.no + " ");
            //终止条件
            if (cur.next == head) {
                break;
            }
            cur = cur.next;
        }
    }

    //根据用户输入 计算出圈顺序
        public void countNode(int startNo, int countNum, int nums) {
            /**
             * startNo示从第几个人开始数
             * countNum表示数几下
             * nums表示人的数量
             */
        if (this.head == null || startNo < 0 || startNo > nums) {
            return;
        }
        //需要一个辅助节点时最后一个节点
            Node tmp = this.head;
            while (true) {
                if (tmp.next == head) {
                    break;
                }
                tmp = tmp.next;
            }
         //从第start开始数数
            for (int i = 0; i < startNo-1; i++) {
                head = head.next;
                tmp = tmp.next;
            }
         // 循环出圈
            while (true) {
                if (tmp == this.head) {
                    break;
                }
                for (int i = 0; i < countNum-1; i++) {
                    head = head.next;
                    tmp = tmp.next;
                }
                //head所指的节点出圈
                System.out.printf("%d号出圈",head.no);
                System.out.println();
                head = head.next;
                tmp.next = head;
            }
            System.out.printf("最后留在圈中的%d号",head.no);
    }
}


。。。

发布了51 篇原创文章 · 获赞 14 · 访问量 2322

猜你喜欢

转载自blog.csdn.net/qq_41185460/article/details/102986841