showliuzp 2025-10-18 17:42 采纳率: 84.3%
浏览 6
已结题

golang链表节点删除通过回调函数的方式


//链表

//并发安全单链表
type SingleNode struct {
    Data interface{}
    Next *SingleNode
}

type SingleList struct {
    mutex *sync.RWMutex //读写锁

    Head  *SingleNode   //头节点
    Tail  *SingleNode   //尾节点

    Size  uint          //总数
}

func NewList() *SingleList {
    return &SingleList{
        Size:  0,
        Head:  nil,
        Tail:  nil,
        mutex: new(sync.RWMutex),
    }
}

//后插元素
func (List *SingleList) LastAppend(node *SingleNode) bool {
    if node == nil {
        return false
    }

    List.mutex.Lock()

    defer List.mutex.Unlock()

    if List.Size == 0 {
        List.Head = node
        List.Tail = node
        List.Size = 1
        return true
    }

    tail := List.Tail
    tail.Next = node
    List.Tail = node
    List.Size += 1

    return true
}


// 删除链表中的指定值节点
func (List *SingleList) DelLinkedNode(f func(data interface) bool) bool {
    if list.Size == 0 {
        return false
    }

    List.Mutex.Lock()

    defer List.Mutex.Unlock()

    var prev *SingleNode = nil
    current := List.Head
    for current != nil {
        f()
        /*conn, ok := current.Data.(ChatWebSocketConn)
        if ok && conn.client_id == client_id {
            if prev == nil {
                List.Head = current.Next
            } else {
                prev.Next = current.Next
            }

            List.Size--

            if List.Size == 0 {
                List.Tail = nil
            }

            return true
        }*/

        prev = current
        current = current.Next
    }

    return false
}

//链表使用
    //建立账号和连接的绑定关系,并作为链表的一个节点
    item := ChatWebSocketConn{
        user_conn       : tools.WebSocketConnMapOnce.ConnMap[client_id],
        client_id          :   *client_id,
        user_type       : (*user_info).Flag,
        user_id         : (*user_info).Id,
        user_nickname   : (*user_info).NickName,
    }

    linked_node := tools.SingleNode{Data:item}
    linked_list.LastAppend(&linked_node)

//ChatWebSocketConn定义
type ChatWebSocketConn struct{
    user_conn       *tools.WebSocketConn            //已建立的客户端连接,lu_guild_account_list表id
    client_id       string                          //生成的唯一id,标识一个客户端
    user_type       int                             //用户类型,1:会员 2:主播
    user_id         int64                           //用户id
    user_nickname   string                          //用户昵称
}


我在实现单链表的删除节点功能,函数定义DeleteNode,添加节点是通过LastAppend将ChatWebSocketConn做为一个Node节点添加进去的,删除的时候需要遍历该节点存储的client_id并进行比对,但感觉对链表的删除仍有侵入,我在DelLinkedNode定义了一个回调函数,我想通过回调函数对存储的值就行对比,根据返回值觉得链表的Next指向,应该怎么完善这个回调函数
  • 写回答

2条回答 默认 最新

  • 紫雾凌寒 新星创作者: 人工智能技术领域 2025-10-18 17:43
    关注

    让 “紫雾凌寒” 来帮你回答,本回答结合 DeepSeek

    如果还有问题,请评论或点击头像私信,如果有帮助到您, 请关注、采纳、点赞

    1. 关键点分析
      - 要实现通过回调函数删除链表节点,需要在链表结构体中添加相关方法,能够遍历链表并根据回调函数的条件来决定是否删除节点。
      - 由于是并发安全的单链表,在进行删除操作时要注意锁的使用,避免并发冲突。
    2. 解决方案
      - 首先完善链表结构体定义:
    //并发安全单链表
    type SingleNode struct {
        Data interface{}
        Next *SingleNode
    }
    
    type SingleList struct {
        head *SingleNode
        lock sync.Mutex
    }
    
    • 然后添加删除节点的方法:
    package main
    
    import (
        "fmt"
        "sync"
    )
    
    //并发安全单链表
    type SingleNode struct {
        Data interface{}
        Next *SingleNode
    }
    
    type SingleList struct {
        head *SingleNode
        lock sync.Mutex
    }
    
    // 添加节点到链表尾部
    func (sl *SingleList) Append(data interface{}) {
        newNode := &SingleNode{Data: data}
        sl.lock.Lock()
        defer sl.lock.Unlock()
        if sl.head == nil {
            sl.head = newNode
        } else {
            current := sl.head
            for current.Next != nil {
                current = current.Next
            }
            current.Next = newNode
        }
    }
    
    // 通过回调函数删除节点
    func (sl *SingleList) DeleteByCallback(callback func(interface{}) bool) {
        sl.lock.Lock()
        defer sl.lock.Unlock()
        current := sl.head
        var prev *SingleNode
        while current != nil {
            if callback(current.Data) {
                if prev == nil {
                    sl.head = current.Next
                } else {
                    prev.Next = current.Next
                }
            } else {
                prev = current
            }
            current = current.Next
        }
    }
    
    1. 代码示例说明
      - SingleList结构体包含一个指向链表头节点的指针head和一个互斥锁lock,用于并发安全。
      - Append方法用于向链表尾部添加节点,添加时先加锁,操作完成后解锁。
      - DeleteByCallback方法通过遍历链表,对每个节点的数据应用回调函数callback。如果回调函数返回true,则删除该节点。删除时需要考虑当前节点是否为头节点,如果是则更新头节点;否则更新前一个节点的Next指针。
    2. 多种解决方案及优缺点
      - 方案一:使用递归
      • 优点:代码结构简洁,对于一些简单的链表操作逻辑清晰。
      • 缺点:递归深度过大时可能导致栈溢出,并且递归调用会增加额外的开销。
      • 方案二:使用迭代(如上述代码)
      • 优点:性能较好,不会出现栈溢出问题,适用于大多数情况。
      • 缺点:代码相对递归来说不够简洁,逻辑上可能稍复杂一些。
    3. 总结
      通过在并发安全的单链表结构体中添加DeleteByCallback方法,利用回调函数来灵活地删除链表节点。这种方式可以根据不同的业务需求定制删除条件,同时通过互斥锁保证了并发操作的安全性。迭代的实现方式在性能和稳定性上表现较好,是一种常用的链表节点删除实现策略。

    请注意,上述代码中while循环在Go语言中可以使用for循环替代,并且代码中SingleLi未完成定义,这里按照补充完整链表结构体的思路进行了完善。如果有其他特殊需求,请根据实际情况调整。

    希望以上解答对您有所帮助。如果您有任何疑问,欢迎在评论区提出。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 10月26日
  • 已采纳回答 10月18日
  • 创建了问题 10月18日