单向循环链表求解约瑟夫环

版权声明:本文为博主原创文章,转载请注明出处 https://blog.csdn.net/yanglong_blog_/article/details/76387982

问题后面的小故事:
       公元66年,约瑟夫参与领导了犹太同胞反抗罗马统治的起义,起义失败,他和一些宁死不降的起义者被困于一个山洞之中。罗马将军派人来劝降,他主张投降,其余的人不答应,并以死相逼。最后,约瑟夫提议,与其死在自己的手上,不如死在彼此的手上。他提出了从第一个人开始,每数到三,则第三个人自杀,从下一个人开始继续从1开始数,每数到三,则第三个人继续自杀…..直到所有人都死亡为之,就这样执行下去,最后只有他和另外一人出了山洞投降。这个问题被后来人们称为约瑟夫环.

求解思路:
       采用单向循环链表,每个人代表一个结点,假设1号是头结点,从头结点开始数,数到3,则先打印第3个人的编号,继续向下数,直到所有的结点都被遍历一遍,循环结束。

输入输出描述:
       假设输入 n 个人, 数到第 m 个人,删除第m个人,
如 n = 41, m = 3, 则删除顺序为 3 -> 6 -> 9 -> 12 -> 15…..

结点代码:

public class Node {
    int c;
    Node next;

    public Node() {
    }

    public Node(int c, Node next) {
        super();
        this.c = c;
        this.next = next;
    }
}

主函数代码:

/*
* @Description: 求解约瑟夫环
*               假设有 n 个结点,从第一个结点开始数,每数到m,第m个人  *            出列(这里就先打印第m个结点的值,再删除m结点)
*               使用单向循环链表
*               最后输出被删除的先后顺序,即m的删除顺序
*/
public class Test {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n;  // 结点个数
        int m;  // 第m出列
        System.out.print("Input N and M:");
        n = sc.nextInt();
        m = sc.nextInt();

        //声明n个结点
        Node[] node = new Node[n];
        //为每个结点赋值
        for(int i=0; i<node.length; i++){
            node[i] = new Node(i+1, null);
        }
        //将第一个结点指向下一个结点
        for(int i=0; i<node.length-1; i++){
            node[i].next = node[i+1];
        }
        //将最后一个结点指向第一个结点,构成一个环
        node[node.length-1].next = node[0];

        //先将p指向第一个结点, p在以后表示要删除结点的前驱结点
        Node p = node[0];

        int k = 0; //控制输入的一行的个数

        // 只要还有结点,就继续循环,即结点p自己指向自己,循环结束
        while(p.next != p ){
            //找到被删除结点的前驱结点
            for(int i=0; i<m-2; i++){
                p = p.next;
            }
            //每输出6个元素输出一个换行
            if (k % 6 == 0){
                System.out.format("\n %02d - ", p.next.c);
            }else{
                System.out.format(" %02d - ", p.next.c);
            }
            k++;
            //删除 p的后继结点, 即被出列的结点
            Node s = p.next;
            p.next = s.next;
            s.next = null;

            //最后使p指向开始数的第一个结点,即被删除结点的下一结点
            p = p.next;  
        }
        //输出最后一个结点
        System.out.format(" %02d", p.c);

        sc.close();//关闭输入流
    }
}   

运行效果图:
这里写图片描述

源码下载:
约瑟夫环源码下载(点击我即可下载)

猜你喜欢

转载自blog.csdn.net/yanglong_blog_/article/details/76387982