一:什么是循环双向链表
双链表每个节点既可以找到它之前的节点,也可以找到之后的节点,是双向的。循环链表,就是它一直往下找数据节点,最后回到了自己那个节点,形成了一个回路。循环单链表和循环双链表的区别就是,一个只能一个方向走,一个两个方向都可以走。总结:循环双向链表就是双链表和循环链表的结合体。
(1)循环双向链表的结构体
type Ring struct {
prev *Ring // 指向前一个节点
Value interface{} // 数值
next *Ring // 指向后一个节点
}
(2)头节点,尾节点
在这里,头节点默认是第一个的那个节点为头节点,头节点中pre指针指向的那个节点为尾节点。
二:循环链表里面的方法
(1)初始化一个空的循环链表
//只有一个节点,然后该节点的prev和next指针都指向自身
func (r *Ring) init() *Ring {
r.prev = r
r.next = r
return r
}
(2)获取链表长度
// 获取链表长度
func (r *Ring) GetLen() int {
//先获取头节点
HeadNode := r
//获取头节点的下一个节点,就是第二个节点
currentNode := r.next
//定义一个len ,这个len初始值为1,因为currentNode是指向第二个节点的,可以画图来理解一下
len := 1
for {
if r.next == HeadNode && r.prev == HeadNode {
// fmt.Println("GetLen里只有一个节点")
return 1
}
currentNode = currentNode.next
len = len + 1
i f currentNode == HeadNode {
return len
}
}
}
(3)获取链表某个位置的值
// 获取链表某个位置的值 这个位置是从1开始 ,而不是按下标索引0开始 ,在这里下标索引0就等于位置1
func (r *Ring) GetValue(n int) int {
//首先把节点移到某个位置
r = r.Move(n)
//进行获取工作
return r.Value.(int)
}
(4)向链表尾端增加节点
// 向链表尾端增加节点,返回值是指向头节点的指针
func (r *Ring) AddNode(node *Ring) *Ring {
HeadNode := r
//获取链表长度
len := r.GetLen()
//把指针移到最后的一个节点
r = r.Move(len)
//如果链表为nil,则自己先形成一个闭环,然后再增加节点
if r.next == nil {
r.init()
}
r.next.prev = node
node.next = r.next
r.next = node
node.prev = r
return HeadNode
}
(5)移动指针到相应位置
// 移动指针到相应的位置,然后的是指向相应节点的指针
func (r *Ring) Move(n int) *Ring {
//先获取链表长度
len := r.GetLen()
//如果n大于len 则做求余数处理
if n > len {
n = n % len
//fmt.Println("len的长度为,", len, "求余后的位置,", n)
}
//首先把节点移到某个位置
for i := 1; i < n; i++ {
r = r.Next()
}
return r
}
(6)获取指针指向当前节点的下一个节点
func (r *Ring) Next() *Ring {
return r.next
}
(7)获取指针指向当前节点的上一个节点
func (r *Ring) Prev() *Ring {
return r.prev
}
(8)在某个位置插入节点
// 在某个位置插入节点
func (r *Ring) InsertKnot(n int, node *Ring) *Ring {
HeadNode := r
//先把指针移动到对应的位置
r = r.Move(n)
//执行插入工作
r.prev.next = node
node.prev = r.prev
node.next = r
r.prev = node
return HeadNod
}
(9)删除某个节点 按位置删除
// 删除某个节点 按位置删除,然后返回的是头指针
func (r *Ring) DeleteKnot(n int) *Ring {
HeadNode := r
if r.GetLen() == 1 {
fmt.Println("返回的是空指针")
return nil
}
if n == 1 {
HeadNode = r.next
}
//先把指针移动到对应的位置
r = r.Move(n)
r.prev.next = r.next
r.next.prev = r.prev
r.prev = nil
r.next = nil
return HeadNode
}
(10)删除链表中的某个值
// 返回的就是头节点了
func (r *Ring) DeleteValue(value int) *Ring {
len1 := r.GetLen()
//定义一个切片,存放要删除的值对应的节点
var nodePositions = make([]int, 0, len1)
for i := 1; i <= len1; i++ {
if r.Value.(int) == value {
nodePositions = append(nodePositions, i)
}
//最终指向r指向头节点
r = r.next
}
nodePositionsLen := len(nodePositions)
//因为删了一个节点后,其它节点的位置也是会变得,所以用一个sub来记录删了多少个节点了
sub := 0
HeadNode := r
for i := 1; i <= nodePositionsLen; i++ {
nodePosition := nodePositions[i-1]
if r != nil {
r = r.DeleteKnot(nodePosition - sub)
sub = sub + 1
}
HeadNode = r
}
return HeadNode
}
三:定义一个函数直接初始化一个n个节点的循环链表
//初始化n个节点的循环链表,值为空
func New(n int) *Ring {
//先判断n是否大于0
if n < 0 {
return nil
}
//先创建一个头节点
r := new(Ring)
p := r
//创建剩下的节点
for i := 1; i < n; n++ {
p.next = &Ring{prev: p}
p = p.next
}
//然后连成一个循环
p.next = r
r.prev = p
return r
}
四:main函数
func main() {
// 使用 defer 和 recover 捕获并处理 panic
defer func() {
if r := recover(); r != nil {
// 捕获到 panic,打印自定义错误信息
fmt.Println("捕获到 panic:", r)
fmt.Print("空指针错误")
}
}()
// 创建一个包含 1、2、3、4、5 的循环链表
r := &Ring{Value: 2}
r = r.init()
HeadNode := r
fmt.Println("原来的长度", r.GetLen())
r = r.AddNode(&Ring{Value: 5})
r = r.AddNode(&Ring{Value: 5})
r = r.AddNode(&Ring{Value: 5})
r = r.AddNode(&Ring{Value: 5})
fmt.Println("原来的长度", r.GetLen())
r = r.DeleteValue(5)
fmt.Println("按值删除后的长度", r.GetLen())
fmt.Println(r.Value.(int))
fmt.Println(r.next.Value.(int))
fmt.Println("==================")
//先打印第一个节点数值
fmt.Println(r.Value)
//从第二个节点开始遍历,输出节点数值
current := r.next
for {
if current == HeadNode {
break
}
if current != nil {
fmt.Println(current.Value)
current = current.next
}
}
//按位置删除第一个位置
r = r.DeleteKnot(1)
fmt.Println(r.GetLen()) //这一个是会出错的,因为r这时候为nil
}
五:总结
链表
和数组
可以用来辅助构建各种基本数据结构,我们可以自己定义各种数据结构