约瑟夫(丢手绢)问题

这篇博客介绍了一个用Scala编写的丢手绢游戏模拟程序,通过初始化单向环形链表来表示参与游戏的小孩。首先创建Boy类表示每个小孩,然后在BoyGame类中构建链表并实现游戏逻辑。游戏开始时,根据输入的参数确定从哪个位置开始数,数到指定次数的小朋友会被淘汰。程序提供了添加小孩、展示所有小孩和开始游戏的方法,可以观察到游戏过程并找出最后留在圈中的小朋友。
摘要由CSDN通过智能技术生成

初始化单向环形链表请添加图片描述

丢手绢示意图

请添加图片描述

实现代码

package linkedlist.josephu

import scala.util.control.Breaks._

object Josephu {

  def main(args: Array[String]): Unit = {
    val boyGame = new BoyGame
    boyGame.addBoy(7)
    //    boyGame.showBoy()
    boyGame.playGame(4, 3, 7)
  }

}

class Boy(num: Int) {
  val no: Int = num
  var next: Boy = null
}


class BoyGame {
  // 定义一个初始的头节点
  private var firstBoy = new Boy(-1)

  // 初始化形成单向环形节点
  def addBoy(nums: Int): Unit = {
    if (nums < 1) {
      println("nums的值不正确")
      return
    }
    var curBoy: Boy = null // 辅助指针
    for (num <- 1 to nums) {
      val boy = new Boy(num)
      if (num == 1) {
        firstBoy = boy
        boy.next = firstBoy //形成一个环形链表
        curBoy = firstBoy
      } else {
        curBoy.next = boy
        boy.next = firstBoy //形成一个环形链表
        curBoy = boy
      }
    }
  }

  def showBoy(): Unit = {
    if (firstBoy.next == null) {
      println("没有任何小孩")
    }
    var curBoy = firstBoy
    breakable {
      while (true) {
        printf("小孩编号:%d\n", curBoy.no)
        if (curBoy.next == firstBoy) {
          break
        }
        curBoy = curBoy.next
      }
    }
  }

  /**
   *
   * @param startNum 开始数的位置
   * @param countNum 数的次数
   * @param totalNum 总的有多少人
   */
  def playGame(startNum: Int, countNum: Int, totalNum: Int): Unit = {

    // 参数合理性校验
    if (startNum < 1 || startNum > totalNum || countNum < 1 || firstBoy.next == null) {
      print("参数不对,无法完成")
      return
    }

    // 1、找到链表的first前面一个指针
    var helper = firstBoy
    breakable {
      while (true) {
        if (helper.next == firstBoy) {
          break()
        }
        helper = helper.next
      }
    }
    // 2、从第几个小朋友还是数i
    for (i <- 0 until startNum - 1) {
      firstBoy = firstBoy.next
      helper = helper.next
    }
    // 3、开始一直数,直到只剩下一个小朋友在圈里
    breakable {
      while (true) {

        // 如果只剩下最后一个的时候下面条件满足
        if (helper == firstBoy) {
          break()
        }

        // 一个一个围着数,firstBoy就是本次出圈的小朋友
        for (i <- 0 until countNum - 1) {
          firstBoy = firstBoy.next
          helper = helper.next
        }
        printf("小朋友%d 出圈\n", firstBoy.no)

        // 踢出圈,只需要把当前小朋友的指针指向下一位,并把后面的指针跟着移动
        firstBoy = firstBoy.next
        helper.next = firstBoy
      }
    }
    printf("小朋友%d是最后一位出圈\n", firstBoy.no)
  }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值