欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

golang环形链表实现约瑟夫问题

程序员文章站 2022-04-21 18:57:23
...

golang环形链表实现约瑟夫问题

约瑟夫问题:是一个出现在计算机科学和数学中的问题,在计算机编程算法中类似问题又称为约瑟夫环或者叫做“丢手帕问题”。

约瑟夫问题的原理:n个人围成一圈,选择一个人开始报数,每过m次则当前报数的人则会被踢出圈,然后挨着的下一个人作为又一轮游戏的第一个报数的人,这样重复最后只会剩下一个人。

例如: n = 6, m = 5,陆续被踢出圈的人的编号为:5,4,6,2,3,1.

代码实现如下:

package main

import "fmt"

// 约瑟夫问题
// 小孩
type Boy struct {
	no   int // 小孩编号
	next *Boy
}

// 编写一个函数构成单向的环形链表
// num表示约瑟夫中小孩的个数,返回环形链表的第一个小孩,也就是头结点
func AddBoy(num int) *Boy {
	head := &Boy{}
	curBoy := &Boy{}
	if num < 1 {
		return head
	}
	// 循环构建环形链表
	for i := 1; i <= num; i++ {
		boy := &Boy{
			no:   i,
			next: nil,
		}
		if i == 1 {
			head = boy
			curBoy = boy
			curBoy.next = head
		} else {
			curBoy.next = boy
			curBoy = boy
			curBoy.next = head
		}
	}
	return head
}

// 打印
func showBoy(head *Boy) {
	temp := head
	for {
		fmt.Println("boy: ", temp.no)
		if temp.next == head {
			break
		}
		temp = temp.next
	}
}


// 求出最后一个小孩,first为编号为1的小孩,startNo为游戏开始的小孩的编号,countNum为游戏规则的间隔
func playGame(first *Boy, startNo, countNum int) {
	if first.next == nil {
		fmt.Println("就一个小孩玩游戏,玩不了")
		return
	}
	// 找到first的前一个节点,由于为环形链表最后一个节点的next就是first头结点,用于判断整个环形链表最后只剩下一个小孩了
	tail := first
	for {
		if tail.next == first {
			break
		}
		tail = tail.next
	}
	// 找到游戏开始的小孩
	startNode := first
	for {
		if startNode.no == startNo {
			break
		}
		startNode = startNode.next
		// tail也要跟着移动
		tail = tail.next
	}
	for {
		// 一轮游戏
		for i := 1; i <= countNum; i++ {
			startNode = startNode.next
			tail = tail.next
		}
		fmt.Println("退出的小孩:", startNode.no)
		if startNode == tail {
			fmt.Println("最后剩下的小孩编号:", startNode.no)
			break
		}
		startNode = startNode.next
		tail.next = startNode
	}
}

func main() {
	// 构造五个节点的环形链表
	head := AddBoy(5)
	// 打印
	showBoy(head)
	// 游戏
	playGame(head, 3, 2)

}

golang环形链表实现约瑟夫问题