Go:用go语言解决Joseph问题

前言:

前段时间忙,一直没有更新。疫情期间,只能闭关在家,继续研究go,编写了不少算法,慢慢上传更新吧😂,也算给我未来的儿子留点笔记😂😄。

用Go编写一个环形单链表,解决Joseph的问题。要求如下:

设编号为1,2....n的n个人围坐一圈,约定的编号为k(1 <=k <=n) 的人,从1开始报数,数到m(1<=m<=n)的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。

代码部分

package main

import (
	"fmt"
	"os"
)

//定义一个结构体
type Children struct {
	No   int
	Next *Children //默认值为nil
}

//构建单向环形链表
//num: 要构建的环形链表的小孩的数量
//*Children 返回一个头指针
func AddChild(num int) *Children {
	first := &Children{}    //空节点
	curChild := &Children{} //辅助指针
	if num < 1 {
		fmt.Println("wrong num")
		return nil
	}
	//循环的构建
	for i := 1; i <= num; i++ {
		child := &Children{
			No: i,
		}
		//第一个小孩比较特殊
		if i == 1 { //第一个小孩
			first = child //将first指针指向第一个节点
			curChild = child
			curChild.Next = first //构成圆环 (如果只有一个节点,则自己指向自己)
		} else {
			curChild.Next = child
			curChild = child
			curChild.Next = first //构成圆环
		}
	}
	return first
}

//显示
func Show(first *Children) {
	if first.Next == nil {
		fmt.Println("empty circleLink")
		return
	}
	//创建一个辅助指针,帮助遍历
	helper := first
	for {
		fmt.Printf("child[%d] ->", helper.No)
		//遍历退出条件 ,当helper.Next = first , 即运行重叠了
		if helper.Next == first {
			break
		}
		//helper 向下移动
		helper = helper.Next
	}
	println()
}

func Sum(first *Children) (total int) {
	if first.Next == nil {
		fmt.Println("empty circleLink")
		return
	}
	//先创建一个辅助指针,帮助遍历
	curChild := first
	total = 0
	for {
		total ++ 
		//遍历退出条件 ,当curChild.Next = first , 即运行重叠了
		if curChild.Next == first {
			break
		}
		//curChild 向下移动
		curChild = curChild.Next
	}
	return total
}

//编写一个算法,按照要求,在环形链表中留下最后一个人

func josephLink(first *Children, startNo, countNum int) {
	//
	if first.Next == nil {
		fmt.Println("empty link")
		return
	}
	//判断if startNo > 小孩的总数,退出
	totalChild := Sum(first)
	if startNo > totalChild || startNo <= 0 {
		fmt.Println("wrong startNo")
		os.Exit(0)
	}
	//需要定义辅助指针,以帮助删除被点到数的小孩
	rear := first
	for {
		if rear.Next == first { //表示rear已经到了最后
			break
		}
		rear = rear.Next //向前移动
	}
	//让first移动到startNo的位置,即删除
	for i := 1; i <= startNo - 1; i++ {
		//同时移动
		first = first.Next
		rear = rear.Next
	}
	println()
	//开始数countNum,然后就删除first 指向的小孩
	for {
		//开始数countNum -1 次
		for j := 1; j <= countNum - 1; j++ {
			first = first.Next
			rear = rear.Next
		}
		fmt.Printf("[%d] removed\n",first.No)
		//删除first指向的节点
		first = first.Next
		rear.Next = first
		//退出判断 当rear == first ,说明圈中只有一个小孩了
		if rear == first {
			break
		}
	}
	fmt.Printf("the last child is [%d]\n",first.No)
}

func main() {
	first := AddChild(10)

	Show(first)
	josephLink(first,6,5)
}

输出结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值