约瑟夫问题~秒懂版

这篇博客介绍了如何使用单向环形链表解决一个经典的算法问题——报数杀人。在有n个人的场景下,从第1个人开始报数,每报到m的人会被淘汰,直到剩下最后一个人。作者通过定义first和prev两个指针来模拟链表操作,详细阐述了如何删除节点并更新链表,最终找到存活者。代码实现过程中考虑了数据有效性检查,并给出了完整的Java代码示例。
摘要由CSDN通过智能技术生成
  • 问题描述

有n个人,编号为1~n,从第一个人开始报数,从1开始报,报到m的人会死掉,然后从第m+1个人开始,重复以上过程。在死了n-1个人后,问最后一个人的编号是?                

不找规律,直接举例子,假设如下

  • 开始位置是第1个人
  • 每次查2个人
  • 总共有9个人

指针的定义

定义两个指针(变量)

  • first:用于记录要被干死的人
  • prev:用于记录要被干死的前一个人,目的就是连接后续的链表
//要先建立一个单向环形链表,这里省略
Node first = head;  (head就代表开始的位置)
Node prev = first;
while(true){
    if(prev.next==first){//此时prev就指向first前一个位置
        break;
    }
    prev=prev.next;
}

指针的移动

如图,此时first就是要干死的人。那么接下来要做的就是单向循环链表的踢出工作。

很显然,要删除first,就要将first前移,用prev直接连first。这样就将这个人干死了

first=first.next;           //first前移
prev.next=first;            //prev指向新的first

 此时,first指向3号位置,由于3还没被查,所以下一次就是从3开始!查两个!注意了,第一次是从1开始查的,1同样也没被查,很显然这里是一个循环。

那么下一个被干死的就是4号,然后first移动到5号位置,那么被干死的就是6号,以此类推、、、

代码!代码!代码!来了,嘿嘿

     /**该方法我是直接从我项目中粘的,有些内容不全,我会做出解释
     * 
     * @param start 起始位置
     * @param step  步长
     * @param nums  队伍总人数
     */
    void outOfRanks(int start, int step, int nums) {
        //确保数据有效性,first==null时,就说明循环链表为空
        if (first == null || start > nums || nums <= 0 || start <= 0) {
            System.out.println("输入数据有误");
            return;
        }

        //定义prev变量。
        //first用于指向结点1
        Child prev = first;    
        while (true) {
            if (prev.next == first) {
                break;
            }
            prev = prev.next;
        }
        //循环结束后,此时的prev就是first前一个结点

        //根据输入的参数,确定起始位置
        for (int i = 0; i < start - 1; i++) {
            prev = prev.next;
            first = first.next;
        }

        //每次循环都干死一个人,那么循环nums-1次,那就干死nums-1个人,剩下的那个就是活着的人
        for (int i = 1; i < nums; i++) {
            //当prev==first时,就剩一个结点了,自身结点next指向自己。退出循环
            if (prev == first) {
                break;
            }
            //开始查人,由于first自身也要查,那么prev和first都向前移动step-1个
            for (int j = 0; j < step - 1; j++) {
                first = first.next;
                prev = prev.next;
            }
            System.out.println("第" + i + "个淘汰的是" + first);
            //再将first前移一个位置,用于删除该节点,也就是把这人干死
            first = first.next;
            prev.next = first;
        }
        System.out.println("活着的是" + first);//这里类中要记得重写toString
    }

 完事!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值