循环单向链表解决约瑟夫问题

约瑟夫问题:
设编号为1,2,…n的人围成一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人再出列,以此类推,直到所有人都出列,由此产生出一个出队列编号的序列。
这里n个人围成一圈,依次出队,这跟我们学到到的循环链表很像,因此我们就通过循环链表来模拟出队情况。
首先,需要设计一个节点类型Person,包含num和next两个属性:

class Person{
    int num;//编号
    Person next;//指向下一个人
}

然后创建链表,设计链表类时,我们在链表类中设计一个head节点,用于表示头节点,然后链表类需要包含添加指定个数节点和出队两个方法。
实现代码如下:

public class JosephuDemo {
    public static void main(String[] args) {
        SingleLinkedList linkedList = new SingleLinkedList();
        linkedList.addPerson(5);//5个人
        linkedList.out(1,2);//从第一个人开始,每次数到2出队
    }
}
class SingleLinkedList{
    private Person head = null;

    /**
     * 环形链表中添加nums个节点
     * @param nums
     */
    public void addPerson(int nums){
        if(nums < 1){
            System.out.println("nums的值不正确");
            return;
        }

        Person tmp = null;//用于标识第几个节点
        for (int i = 1; i <= nums; i++) {
            Person p = new Person(i);
            if(i == 1){
                head = p;
                head.next = head;
                tmp = head;
            }else {
                tmp.next = p;
                p.next = head;
                tmp = tmp.next;
            }
        }
    }

    /**
     * 约瑟夫出队
     * @param k
     * @param m
     */
    public void out(int k, int m){
		//定义一个tmp,相当于一个游标,用来遍历链表中的节点。首先指向头节点
        Person tmp = head;
        //遍历链表节点,找到编号为k的节点的前一个节点(因为这里是单链表,所以只有指向编号为k的前一个节点,在数数之后,才好对要出队的节点进行删除操作)
        while (tmp.next.num != k) {
            tmp = tmp.next;
        }//循环结束到达编号为k的前一个人
        //开始数数
        while (tmp.next != tmp) {//当tmp.next == tmp时,说明当前链表中只剩下一个头节点,也就是圈中只有一个人了
            //这里注意,由于数m个后,tmp指向了要出队的人,不好进行删除动作,所以只数m-1次
            for (int i = 0; i < m - 1; i++) {
                tmp = tmp.next;
            }
            System.out.println(tmp.next.num);
            //tmp的下一个人出列
            tmp.next = tmp.next.next;
        }
        //删除最后一个人
        System.out.printf("最后出圈的人是%d" ,tmp.num);
        tmp = null;
    }
}

class Person{
    int num;//编号
    Person next;//指向下一个人

    public Person(int num) {
        this.num = num;
    }

    @Override
    public String toString() {
        return "Person{" +
                "num=" + num +
                '}';
    }
}

代码运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值