Java实现约瑟夫问题

约瑟夫问题
概述:
一共有n个人围成一圈,事先给定两个值k,m,其中k代表一开始从第k个人开始数1,m代表数到m的人出圈,每次出圈一个人,从出圈的那个人的下一个人继续从1开始数,数到m的人再出圈,如此循环,直到最后一个人留在圈里,这样我们就可以得到一个按出圈顺序排列的数的序列。

根据这样的问题,我们利用java来编程实现:
主要思想:

1、创建一个小孩类,其拥有自身的元素值,又能够指向下一个小孩

2、创建一个环形链表代表一个圈,每次出圈一个小孩,就将其上一个小孩的nextchild指向其下一个小孩,这样就相当于出圈了,即从环形链表中删除

3、出圈的动作是一直进行的,直到剩下最后一个小孩,我们需要设置环形链表的长度len,即开始游戏之前一共有多少个小孩参加游戏,每次出圈len减一

/**
 * Author:MrBread
 * Function:解决约瑟夫问题
 * Date:2017-03-29
 */
package com.mycode.test;

public class Joseph {
    public static void main(String []args){
        CycleLink cl=new CycleLink();  //创建环形链表对象
        cl.setLen(10);  //设置环形链表的长度
        cl.create();   //初始化环形链表
        cl.setK(2);    //设置k
        cl.setM(2);    //设置m
        cl.play();     //开始游戏
    }
}

//定义一个小孩类
class Child{
    int num;
    Child nextchild;

    //构造函数设置小孩中的num值
    public Child(int num){
        this.num=num;
    }

    public Child(){}
}

//定义一个环形链表
class CycleLink{
    Child firstchild;//定义环形链表的头节点
    Child temp;
    int k=0;  //k代表从第几个小孩开始数
    int m=0;  //m代表数到几就出圈
    int len=0; //代表环形链表中小孩的总数

    //设置环形链表的长度
    public void setLen(int len){
        this.len=len;
    }
    //构造设置k值的方法
    public void setK(int k){
        this.k=k;
    }

    //构造设置m值的方法
    public void setM(int m){
        this.m=m;
    }

    //初始化环形链表,即根据len大小创建具体的小孩
    public void create(){
        for(int i=1;i<=len;i++){
            if(i==1){
                Child ch=new Child(i);
                temp=ch;
                firstchild=ch;
            }else if(i>1&&i<len){
                Child ch=new Child(i);
                temp.nextchild=ch;
                temp=temp.nextchild;
            }else{
                Child ch=new Child(i);
                temp.nextchild=ch;
                temp=temp.nextchild;
                temp.nextchild=firstchild;
            }
        }
    }

    //开始丢手帕游戏,最后按出圈的顺序输出一串数
    public void play(){

        //遍历环形链表找出第k个人
        temp=firstchild;
        for(int i=1;i<k;i++){
            temp=temp.nextchild;
        }
        //跳出循环之后就知道temp指向了开始报数的那个小孩

        while(this.len!=1)  //一直循环,直到剩下最后一个小孩
        {
            //从temp指向的那个小孩开始报1,遍历链表找到数m的那个小孩
            for(int j=1;j<m;j++)
            {
                temp=temp.nextchild;
            }
            //循环结束之后我们就知道temp指向了要出圈的那个小孩

            //打印要出圈小孩的num值
            System.out.println(temp.num);

            //将那个要出圈的小孩请出圈,即删除该小孩
            Child temp2=new Child();
            temp2=firstchild;
            for(int i=1;i<=len;i++){
                if(temp2.nextchild==temp){  //若temp2指向的是要删除小孩的上一个小孩,则跳出循环
                    break;
                }
                temp2=temp2.nextchild;
            }
            temp2.nextchild=temp.nextchild;//完成删除操作
            //让下一个小孩重新从1开始报数
            temp=temp.nextchild;
            this.len--;//每次请出圈就把链表长度减一
        }
        //打印最后一个小孩的num值
        System.out.println(temp.num);
    }
}

测试结果如图:

这里写图片描述


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值