package ds // ds-list.go // 泛型单链表。带哨兵头节点(dummy head),便于在 O(1) 删除首节点时统一处理边界。 // T 约束为 comparable,Delete 的值比较直接用 ==,类型安全且无需 reflect。 // 所有节点指针操作都不依赖切片下标,删除/反转只改指针,不搬移数据。 // ListNode 单链表节点。 type ListNode[T any] struct { Val T Next *ListNode[T] } // LinkedList 单链表,持有哨兵头节点和尾指针。 // head 是哨兵,不存真实数据;真实首节点是 head.Next。 // 尾指针让 PushBack 为 O(1)。 type LinkedList[T comparable] struct { head *ListNode[T] // 哨兵头节点 tail *ListNode[T] // 指向最后一个真实节点;空表时 tail == head } // NewLinkedList 创建空链表。 func NewLinkedList[T comparable]() *LinkedList[T] { dummy := &ListNode[T]{} return &LinkedList[T]{head: dummy, tail: dummy} } // Len 链表长度,O(n)。链表无 size 字段时只能遍历;如需 O(1) 长度可自行加计数器。 func (l *LinkedList[T]) Len() int { n := 0 for cur := l.head.Next; cur != nil; cur = cur.Next { n++ } return n } // Empty 是否为空。 func (l *LinkedList[T]) Empty() bool { return l.head.Next == nil } // PushFront 头插,O(1)。 func (l *LinkedList[T]) PushFront(v T) { node := &ListNode[T]{Val: v, Next: l.head.Next} l.head.Next = node if l.tail == l.head { // 之前是空表,更新尾指针 l.tail = node } } // PushBack 尾插,O(1)。 func (l *LinkedList[T]) PushBack(v T) { node := &ListNode[T]{Val: v} l.tail.Next = node l.tail = node } // Delete 删除第一个值等于 v 的节点,O(n)。返回是否删除成功。 func (l *LinkedList[T]) Delete(v T) bool { prev := l.head for cur := l.head.Next; cur != nil; prev, cur = cur, cur.Next { if cur.Val == v { prev.Next = cur.Next if cur == l.tail { // 删的是尾节点,更新尾指针 l.tail = prev } cur.Next = nil // 断开引用 return true } } return false } // Reverse 整表反转,O(n)。 func (l *LinkedList[T]) Reverse() { var prev *ListNode[T] cur := l.head.Next // 反转后原来的首节点变成尾节点 if cur != nil { l.tail = cur } for cur != nil { next := cur.Next cur.Next = prev prev = cur cur = next } l.head.Next = prev } // ToSlice 顺序转为切片,便于测试和遍历。 func (l *LinkedList[T]) ToSlice() []T { var out []T for cur := l.head.Next; cur != nil; cur = cur.Next { out = append(out, cur.Val) } return out } // Head 返回第一个真实节点(非哨兵),空表返回 nil。供需要直接操作节点的场景使用。 func (l *LinkedList[T]) Head() *ListNode[T] { return l.head.Next }