环形链表——约瑟夫问题

问题描述

Josephu问题:设编号为1,2,3…n的n个人围坐成一圈,约定编号为k的人从1开始报数,数到m的那个人出列,他的下一位从1开始报数,数到m那个人又出列,直到所有人都出列为止,由此产生一个出队列编号的序号。

解决方法
  1. 创建一个辅助指针helper,指向头指针的前一个节点
  2. 当小孩报数的时候,first指针helper指针向后移 m-1
  3. 移动后进行出列,先将first指针后移一位,然后连接help指针
       first = first.next
       helper.next = first

代码部分

  需要实现的功能

  • 建立环形链表,通过输入数字n,确定要建立多少个人的环形链表
  • 遍历打印环形链表
  • 实现约瑟夫算法,输入m确定数几下出列

n=5(五个人)
k=1(从第一个人开始数)
m=2(数两下就出列)

package LinkList;

public class Josephu {

    public static void main(String[] args) {
        Josephu jDemo = new Josephu();
        jDemo.josephu(5,1,2);
    }
    
    /**
     * 约瑟夫算法
     * @param n 环形链表中有多少小孩
     * @param m 数几下进行出圈
     * @param k 从第几个小孩开始报数
     */
    public void josephu(int n, int k, int m)
    {
        CircleSimpleLinkList csl = new CircleSimpleLinkList();
        Boy first = csl.CreateCircleLinkList(n);
        Boy helper = csl.end;
        //在开始之前需要移动到开始位置
        for(int i=0; i<k-1; i++)
        {
            first = first.next;
            helper = helper.next;
        }
        //数数到要出圈的男孩那,进行出圈
        while(true)
        {
            if(helper == first)//到了最后一个人
            {
                break;
            }
            for(int i=0; i<m-1; i++)
            {
                first = first.next;
                helper = helper.next;
            }
            //进行出圈
            System.out.print(first.getNo() + "->");
            first = first.next;
            helper.next = first;
        }
        //输出最后一个男孩
        System.out.println(first.getNo());
    }
}

class CircleSimpleLinkList{
    public Boy head = null;//指向头部
    public Boy end = null;//指向尾部
    //建立环形链表
    public Boy CreateCircleLinkList(int no)
    {
        for(int i = 1; i <= no; i++)
        {
            Boy boy = new Boy(i);
            //判断是否为头节点
            if(i == 1)
            {
                head = boy;
                end = boy;
                end.next = head;
            }else //不为头
            {
                end.next = boy;
                end = boy;
                end.next = head;
            }
        }
        return head;
    }
    //遍历循环链表
    public void showCircleLinkList(Boy head)
    {
        Boy sign = head;//标记
        do{
            System.out.print(sign.getNo() + "->");
            sign = sign.next;
        }while(sign != head);
    }
}

class Boy{
    private int No;
    protected Boy next;
    public Boy(int no)
    {
        this.No = no;
    }
    public int getNo() {
        return No;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值