约瑟夫问题代码实现(Java版)

简要:

    1 丢手绢问题:这是小时候经常玩的游戏,一群小朋友围到一起,形成一个圈。老师唱歌,小朋友们同时丢手绢,歌曲暂停时,目前拿到手绢的小朋友需要表演一个节目。依次循环下去。

    2 而约瑟夫问题与之类似,由一群元素构成的环形链表,首先由某个元素开始报数,报到K时的那个元素需要出圈,然后又由下一个元素开始报数,直到全部的元素出圈时才结束。


下面代码相关的注意点:

相关术语解释
first表示的意思是头结点
last表示的意思是为节点
num表示的意识是添加元素的数量
startNo表示的意思是开始时从哪里数数
count表示的意思是数几下
startNum表示的意思是开始的时候有 多少元素
m表示的意思是报的数是多少


另外:

添加元素是首先first自我成环然后添加元素时改变元素指针的指向。
如:
1 开始环中只有一个元素时:
在这里插入图片描述
2 添加一个元素时:(这里需要用到一个辅助节点curboy,目的是为了添加元素和遍历时更加方便)
在这里插入图片描述
3 出圈的时候:(需要用到两个辅助节点,一个是first,另一个是last,first需要指向需要出圈的元素,last应该在first的后一位。)

  • 未出圈之前:如
    在这里插入图片描述
  • 假如boy2准备出圈此时的情况:(first需要移动到boy2处,last也需要向相同的方向移动相同的位数)
    在这里插入图片描述
  • boy2出圈后(一个元素最多指向另一个元素):
    在这里插入图片描述
  • 最终:
    first = last

相关代码:

public class Test {

    public static void main(String[] args){
        CircleLinkedlist c =new CircleLinkedlist();
        c.add(10);
        System.out.println("遍历后的元素");
        c.list();
        c.count(2,3,10);
    }
}

//创造一个环形链表。
class CircleLinkedlist{
    Boy first = null;
    Boy last = null;
    //在里面有很多进行链表的操作。

    //定义一个添加元素的方法。
    public void add(int num){

        if(num<1){
            System.out.println("num的数值不准确");
        }
        else{
            Boy curBoy = null;    //定义一个辅助节点。
            for(int i=1;i<=num;i++){
                //定义一个男生节点。
                Boy boy = new Boy(i);
                //在这个循环语句内要形成一个环。所以首节点需要形成一个环。
                if(i==1){
                    //自我形成一个环。
                    first =boy;
                    first.next=first;
                    curBoy = first;
                }
                else{
                    curBoy.next=boy;
                    boy.next = first;
                    curBoy = boy;
                }
            }//取最后一次环就行了!!
        }

    }

    //根据用户的输入来判断男孩输出的顺序。
    //startNo表示的意思是刚开始从哪里开始数数。
    //count表示的意思是数几下。
    //startNum表示的意思是刚开始有几个男孩在里面。
    public void count(int startNo,int count,int startNum){
        last = first;

        //先对数据进行校验。
        if(first == null||startNo == 0||count > startNum||startNo > startNum){
            System.out.println("参数输入有误");
        }
        else{
            //首先让last指针指向最后一个节点
            while(true){
                if(last.next==first){
                    break;
                }
                else{
                    last=last.next;
                }
            }
            //,first和last节点分别移动m-1次。此时的first指向开始报数的男孩处。
            for(int i = 1;i<startNo;i++){
                first = first.next;
                last = last.next;
            }
            //出圈。
            while(true){
                //最终两者指向同一个节点。
                if(first==last){   //说明圈中只有一个节点。
                    break;
                }
                else{
                    //得出指向报m次处的男孩处。
                    for(int i=0;i<count-1;i++){
                        first = first.next;
                        last = last.next;
                    }
                    //输出需要出圈小孩的编号和名字。
                    System.out.println("出圈小孩的编号:"+first.no);
                    //实现小孩的出圈操作,需要删除出圈的节点。
                    last.next=null;

                    //获得删除节点的后一个节点,并将last与其连接。
                    Boy temp = first.next;
                    last.next = temp;
                    //设置first.next的值为null
                    first.next = null;    //取消了一根head指向下一个元素的指针。
                    startNum--;    //循环一次,人数减少一个。
                    //移动first指针,移动一位,并指向temp。
                    first = temp;

                }
            }
        }
    }
    //遍历当前的环形链表。。
    public void list(){
        Boy curBoy = null;
        if(first.next==null){
          System.out.println("环形链表元素为空,无法遍历");
        }
        else {
            curBoy = first;    //因为直接用boy不好进行遍历,所以只能寻找一个辅助节点来帮忙。
            while(true){
                if(curBoy.next==first){
                    break;
                }
                else {
                    System.out.println("no = "+curBoy.no);
                    curBoy=curBoy.next;
                }
            }
        }
    }
}
//创造一个Boy类表示一个节点。
class Boy {
    int no;
    Boy next;
    public Boy(int no ){
        this.no = no;

    }
}

代码结果:

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值