思路
約瑟夫環問題 :
題目是 假設有N個小朋友按順序圍成一圈,每個小朋友都有一個編號,假設從第m個小朋友從1開始報數,報到k的小朋友出圈,從出圈的下一個小朋友繼續報數,重複上面的報數。直到所有的人出圈位置。
求出圈的小朋友的順序是什麼
解決方案:
我們使用的是單向的環形鏈表作爲數據結構
思路大致分爲
- 尋找指定開始節點
- 跳動指定的步長-1(需要獲取彈出節點的前一個節點,纔可以做刪除)
- 顯示彈出節點
代碼
package com.xipenhui.cn
import scala.collection.mutable.ArrayBuffer
import scala.util.control.Breaks._
/**
* 約瑟夫環問題 :
* 題目是 假設有N個小朋友按順序圍成一圈,每個小朋友都有一個編號,假設從第m個小朋友從1開始報數
* 報到k的小朋友出圈,從出圈的下一個小朋友繼續報數,重複上面的報數。直到所有的人出圈位置。求出圈
* 的小朋友的順序是什麼
* 解決方案:
* 我們使用的是單向的環形鏈表作爲數據結構
*/
object JosephuDemo {
def main(args: Array[String]): Unit = {
val josephu = new Josephu()
val boys = josephu.addBoy(5)
println("=======創建出來的boys是=======")
josephu.show()
println("===彈出小朋友===")
josephu.popBoy(2,3,5)
}
}
/**
* 環形單向鏈表
* 1. 添加小孩子
* 2. 按照規則彈出小孩子
* 3. 顯示環形隊列的值,做過程校驗
*/
class Josephu {
var head = Boy(-1)
/**
*
* @param num 添加小孩的個數
*/
def addBoy(num: Int) {
//參數校驗
if (num < 1) {
throw new RuntimeException("input num must big than 1")
}
var currBoy: Boy = null
for (i <- 1 to num) {
val boy = new Boy(i)
if (i == 1) {
head = boy
head.next = head
currBoy = boy
} else {
currBoy.next = boy
boy.next = head
currBoy = boy
}
}
}
/**
* 按照給定的規律彈出元素
* 1. 從開始數到第m個小朋友,拿到當前的小朋友
* 2. 在當前節點進行後移,移動到k個小朋友的前一個節點(單向鏈表刪除需要使用前一個節點輔助)
* 彈出當前小朋友,刪除當前節點,
* 3. 這裏可以使用兩個for循環,
* 第一次循環的長度爲鏈表長度
* 第二次循環的長度爲移動的長度 k -1 (因爲要前一個節點)
*
* @param startNum 從第num個位置開發數數字
* @param countNum 數數的長度爲len
* @param len 環形鏈表的長度
*/
def popBoy(startNum: Int, countNum: Int, len: Int): Unit = {
//val resArr = ArrayBuffer[Boy]
if (head.next == null || startNum < 1 || startNum > len) {
println("輸入參數錯誤,請重新輸入")
System.exit(0)
}
var currBoy: Boy = head
//可以找到起始位置的節點
breakable {
while (currBoy.next != head) {
if (currBoy.num == startNum) {
break()
} else {
currBoy = currBoy.next
}
}
}
if (currBoy.next == head) throw new RuntimeException("can not find input element")
//點名的次數爲 len次
for (i <- 0 until len) {
//從currBoy開始點名,點名的長度爲countNum,這裏是單向鏈表,要藉助前一個節點進行刪除
for (j <- 1 until countNum-1) {
currBoy = currBoy.next
}
//這裏 currBoy已經移動到需要移除節點的前一個節點
print(s"output element is ${currBoy.next.num} \n")
currBoy.next = currBoy.next.next
currBoy = currBoy.next
}
}
//顯示當前鏈表的內容
def show(): Unit = {
var currBoy = head
while (currBoy.next != head){
println(s"input boy's num is ${currBoy.num}")
currBoy=currBoy.next
}
println(s"input boy's num is ${currBoy.num}")
}
}
case class Boy(num: Int) {
var next: Boy = null
}