Files
leetcode/data-structure/ds-list.go
T
2026-07-20 19:57:25 +08:00

100 lines
2.6 KiB
Go

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 }