完成对单向环形链表的添加结点,册除结点和显示.
package main
import (
"fmt"
)
//定义猫的结构体的结点
type CatNode struct {
Num int //猫的编号
Name string
Next *CatNode //指向下一个结点
}
//添加结点
func InsertCatNode(head *CatNode,newCatNode *CatNode){
//判断是不是添加第一只猫
if head.Next == nil {
head.Num = newCatNode.Num
head.Name = newCatNode.Name
//第一只猫,自己指向自己 //形成一个环形
head.Next=head
fmt.Println(newCatNode,"join this circelSingleLink")
return
}
//定义一个临时变量,帮忙找到环形的最后结点
temp := head
for {
if temp.Next == head {
break
}
temp = temp.Next
}
//加入到链表中
temp.Next = newCatNode
newCatNode.Next = head
}
//显示链表
func ListCircelLink(head *CatNode){
fmt.Println("This circelLink :")
temp := head
if temp.Next == nil{
fmt.Println("空链表")
return
}
for{
fmt.Printf("猫的信息为=[id= %d name= %s]--> \n",temp.Num,temp.Name)
if temp.Next == head {
break
}
temp=temp.Next
}
}
//删除结点
func DelCatNode(head *CatNode,id int) *CatNode{
temp := head
helper := head
//空链表
if temp.Next == nil {
fmt.Println("这是一个空的环形链表,不能删除")
return head
}
//只有一会结点
if temp.Next == head && temp.Num == id{ //只有一个结点
temp.Next = nil
return head
}
//将helper 定位到链表最后
for{
if helper.Next ==head {
break
}
helper = helper.Next
}
//如果有两个及其以上的结点
flag := true
for{
if temp.Next == head { //如果到这来,说明我比较到最后一个(最后一个还没有比较)
break
}
if temp.Num == id {
if temp == head {//说明删除的是头节点
head = head.Next
}
//恭喜你找到了,可以直接删除
helper.Next =temp.Next //指向temp的下个节点
fmt.Printf("猫被删除了id= %d \n",id)
flag = false
break
}
temp =temp.Next //移动 (比较)
helper = helper.Next//移动 (一旦找到要删除的结点 helper)
}
//在比较一次
if flag { //如果flag为真,则我们上面没有删除
if temp.Num==id {
helper.Next =temp.Next
fmt.Printf("猫被删除了id= %d \n",id)
}else{
fmt.Println("Sorry,This Num Not exist : ",id)
}
}
return head
}
func main(){
//初始化一个环形链表的头结点
head := &CatNode{}
//创建一只猫
cat1 := &CatNode{
Num :1,
Name : "tom" ,
}
cat2 := &CatNode{
Num :2,
Name : "yuanyuan" ,
}
cat3 := &CatNode{
Num :3,
Name : "rourou" ,
}
InsertCatNode(head,cat1)
InsertCatNode(head,cat2)
InsertCatNode(head,cat3)
ListCircelLink(head)
DelCatNode(head,4)
fmt.Println()
ListCircelLink(head)
}
Josephu问题
Josephu_问题为:设编号为1,2,...n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
提示: 用一个不带头结点的循环链表来处理Josephu问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,然后再从被规除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束。
package main
import (
"fmt"
)
type Boy struct{
Num int //编号
Next *Boy //指向下一个结点的指针【默认值是nil】
}
//编写一个函数,构成单向的环形链表
//Num : 表示结点个数
//*Boy : 返回该环形链表的第一个小孩指针
func AddBoy(num int) *Boy{
first := &Boy{} //空结点
curBoy := &Boy{} //空结点
//判断
if num < 1 {
fmt.Println("num的值不对")
return first
}
//循环的构建这个环形链表
for i:=1;i<=num;i++{
boy := &Boy{
Num:i,
}
//分析构成循环链表,需要一个辅助指针
//1.因为第一个小孩比较特殊
if i==1{ //第一个小孩
first=boy
curBoy =boy
curBoy.Next = first //自己指向自己
}else{
curBoy.Next = boy
curBoy=boy
curBoy.Next = first //构造环形链表
}
}
return first
}
//显示单向的环形链表
func ShowBoy(first *Boy){
//处理一下如果环形链表为空
if first.Next == nil {
fmt.Println("空链表")
return
}
//创建一个指针,帮助遍历[说明至少有一个结点]
curBoy := first
for {
fmt.Printf("结点编号=%d -->",curBoy.Num)
//遍历完
if curBoy.Next == first {
break
}
//让curBoy指向下一个结点
curBoy =curBoy.Next
}
}
/*
设编号为1,2,.... n的n个人围坐一圈,约定编号为k(1<=k<=n)
的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,
数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列
*/
//分析
//1.编写一个函数,PlayGame(first *Boy, startNo int,countNum int)
//2.最后我们使用一个算法,按照要求,在环形链表中留下最后一个人
func PlayGame(first *Boy, startNum int,countNum int) {
//1.空的链表我们单独处理
if first.Next == nil{
fmt.Println("空链表")
return
}
//还需要判断startNum <= 结点总数
//2.需要定义辅助指针,帮助删除
tail := first
//3.让tail指向环形链表的最后一个结点,(重要)
for {
if tail.Next == first{ //说明tail到了最后的结点
break
}
tail = tail.Next
}
//4.让first移动到startNum [删除结点,就以first为准]
for i := 1 ;i<=startNum -1 ;i++{
first= first.Next
tail=tail.Next
}
fmt.Println()
//5.开始数countNum ,然后就删除first 指向的结点
for{
//开始数countNum - 1 次
for i:=1;i<=countNum -1 ;i++{
first= first.Next
tail=tail.Next
}
fmt.Printf("结点编号为%d 出圈了\n",first.Num)
//删除first指向的结点
first = first.Next
tail.Next = first
//如果tail == first ,圈中只有一个结点了
if tail == first {
break
}
}
fmt.Printf("结点编号为%d 出圈了 \n",first.Num)
}
func main(){
first := AddBoy(5)
ShowBoy(first)
PlayGame(first,2,3)
}