Golang的数据结构与算法-----循环双向链表

一:什么是循环双向链表

        双链表每个节点既可以找到它之前的节点,也可以找到之后的节点,是双向的。循环链表,就是它一直往下找数据节点,最后回到了自己那个节点,形成了一个回路。循环单链表和循环双链表的区别就是,一个只能一个方向走,一个两个方向都可以走。总结:循环双向链表就是双链表和循环链表的结合体。

        (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

}

五:总结

链表数组可以用来辅助构建各种基本数据结构,我们可以自己定义各种数据结构

                

  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值