环形链表介绍
环形链表是一种特殊的链表结构,其主要特点是链表的尾节点指向头节点或其他节点,从而形成一个环状结构。以下是关于环形链表的详细讲解:
一、定义与特点
环形链表是将单向链表的首尾相连,使得链表中的任意节点都能通过链式关系找到其他任意节点,包括头节点。这种结构使得环形链表在某些特定场景下具有独特的优势。环形链表的节点数不限,但必须至少有一个头节点。在环形链表中插入或删除节点时,需要特别处理,不能破坏原有的环形结构。遍历环形链表时也需要使用特殊的方法,否则可能会陷入死循环。
二、应用场景
环形链表主要用于解决一些具有特殊需求的问题,例如约瑟夫问题。约瑟夫问题是一个经典的数学问题,描述的是编号为1,2,3,...n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止。这个问题可以通过环形链表来方便地解决。
环形链表的实现
通过定义结构体以及给结构体绑定方法进行实现环形链表。
定义结构体
id代表节点的id,name代表节点id对应的内容,next代表存储下一个节点的信息
type LinkedLists struct {
id int
name string
next *LinkedLists
}
添加节点
首先判断添加的是否为第一个节点,如果是就将要添加的节点的id,name都赋值给头节点,头节点的下一个指向头节点,进而形成环形结构。如果原先的环形链表中存在节点,那么建立辅助节点temp,通过循环将辅助节点temp指向链表的最后一个节点,从而将temp的下一个指向要添加的节点,将要添加的节点的下一个指向头节点,即可完成添加操作。
func InputNode(head *LinkedLists, hero *LinkedLists) {
//判断添加的是不是第一个节点
if head.next == nil {
head.id = hero.id
head.name = hero.name
head.next = head
fmt.Println("添加第一个节点成功")
return
}
// 添加辅助节点
temp := head
for {
if temp.next == head {
break
}
temp = temp.next
}
//加入到链表中
temp.next = hero
hero.next = head
删除节点
首先判断是不是空链表,如果是空链表则退出,再进行判断是不是链表只有一个节点,如果是直接将头节点的信息为空,即完成删除操作。如果链表中有两个及两个以上的节点,则通过定义两个辅助节点进行操作,temp节点用于寻找要删除的节点,helper节点用于删除找到的节点操作。首先将helper节点通过循环指向环形链表的最后一个节点,然后通过for循环将temp的id与要删除的id进行对比,定义flag用于判断要删除的节点是不是最后一个节点,如果是则让helper的下一个节点指向temp的下一个节点,即可完成操作,如果不是则继续进行寻找,如果找到要删除的节点,先判断该节点是不是头节点,如果是将头节点指向头节点的下一个,并将helper的下一个节点指向temp的下一个节点,如果不是头节点,那直接执行helper的下一个节点指向temp的下一个节点操作即可。
func DelectNode(head *LinkedLists, id int) *LinkedLists {
//首先判断是不是空链表
if head.next == nil {
fmt.Println("空链表无法执行删除操作")
return head
}
// 只有一个节点的时候的删除操作
if head.next == head {
head.next = nil
return head
}
//有两个以及两个以上的节点的时候的删除操作
//定义两个辅助节点,temp用于寻找要删除的节点,helper用于删除节点操作
//将helper节点指向环形链表的最后一个节点
temp := head
helper := head
for {
if helper.next == head {
break
}
helper = helper.next
}
// 让temp的id与要删除的id进行对比,相同则进行删除操作
//定义flag进行协助删除,主要用于判断是不是删除最后一个节点
flag := true
for {
if temp.next == head {
//这里说明已经找到了最后(不包括最后一个节点)仍然没找到要删除的接待你
break
}
if temp.id == id {
// 说明找到了,进行删除操作
if temp == head {
// 这里说明删除的是头节点
head = head.next
}
helper.next = temp.next
fmt.Println()
fmt.Println("删除掉的节点为:", id)
flag = false
break
}
temp = temp.next
helper = helper.next
}
if flag {
if temp.id == id {
helper.next = temp.next
fmt.Println()
fmt.Println("删除掉的节点为:", id)
} else {
fmt.Println("没有找到要删除的节点id:", id)
}
}
return head
}
显示环形链表
定义辅助节点temp,判断环形链表是否为空,如果为空链表则退出,如果不为空通过for循环打印输出环形链表的各个节点。
func ShowList(head *LinkedLists) {
temp := head
if temp.next == nil {
fmt.Println("空链表")
return
}
for {
fmt.Printf("[%d,%s]---->", temp.id, temp.name)
if temp.next == head {
break
}
temp = temp.next
}
}
完整代码示例
package main
import (
"fmt"
)
type LinkedLists struct {
id int
name string
next *LinkedLists
}
// InputNode 添加节点
func InputNode(head *LinkedLists, hero *LinkedLists) {
//判断添加的是不是第一个节点
if head.next == nil {
head.id = hero.id
head.name = hero.name
head.next = head
fmt.Println("添加第一个节点成功")
return
}
// 添加辅助节点
temp := head
for {
if temp.next == head {
break
}
temp = temp.next
}
//加入到链表中
temp.next = hero
hero.next = head
}
// DelectNode 删除节点
func DelectNode(head *LinkedLists, id int) *LinkedLists {
//首先判断是不是空链表
if head.next == nil {
fmt.Println("空链表无法执行删除操作")
return head
}
// 只有一个节点的时候的删除操作
if head.next == head {
head.next = nil
return head
}
//有两个以及两个以上的节点的时候的删除操作
//定义两个辅助节点,temp用于寻找要删除的节点,helper用于删除节点操作
//将helper节点指向环形链表的最后一个节点
temp := head
helper := head
for {
if helper.next == head {
break
}
helper = helper.next
}
// 让temp的id与要删除的id进行对比,相同则进行删除操作
//定义flag进行协助删除,主要用于判断是不是删除最后一个节点
flag := true
for {
if temp.next == head {
//这里说明已经找到了最后(不包括最后一个节点)仍然没找到要删除的接待你
break
}
if temp.id == id {
// 说明找到了,进行删除操作
if temp == head {
// 这里说明删除的是头节点
head = head.next
}
helper.next = temp.next
fmt.Println()
fmt.Println("删除掉的节点为:", id)
flag = false
break
}
temp = temp.next
helper = helper.next
}
if flag {
if temp.id == id {
helper.next = temp.next
fmt.Println()
fmt.Println("删除掉的节点为:", id)
} else {
fmt.Println("没有找到要删除的节点id:", id)
}
}
return head
}
// ShowList 显示环形链表数据
func ShowList(head *LinkedLists) {
temp := head
if temp.next == nil {
fmt.Println("空链表")
return
}
for {
fmt.Printf("[%d,%s]---->", temp.id, temp.name)
if temp.next == head {
break
}
temp = temp.next
}
}
func main() {
head := &LinkedLists{}
hero1 := &LinkedLists{
id: 1,
name: "花花",
}
hero2 := &LinkedLists{
id: 2,
name: "明明",
}
hero3 := &LinkedLists{
id: 3,
name: "当当",
}
hero4 := &LinkedLists{
id: 4,
name: "坤坤",
}
InputNode(head, hero1)
InputNode(head, hero2)
InputNode(head, hero3)
InputNode(head, hero4)
ShowList(head)
head = DelectNode(head, 1)
ShowList(head)
}