C# 中的 LinkedList

一、概述

LinkedList<T> 是 .NET 标准库(System.Collections.Generic 命名空间)中提供的一种泛型双向链表实现。

其本质特征如下:

  • 采用 双向链表(Doubly Linked List) 结构
  • 每个节点通过引用连接前驱节点和后继节点
  • 不支持基于索引的随机访问
  • 提供高效的节点级插入与删除操作

二、类定义与继承体系

csharp 复制代码
public class LinkedList<T> : 
    ICollection<T>, 
    ICollection, 
    IReadOnlyCollection<T>, 
    IEnumerable<T>, 
    IEnumerable, 
    ISerializable, 
    IDeserializationCallback

关键说明:

  • 不实现 IList<T>

    • 表明其不支持索引访问(如 list[0]
  • 提供集合基础能力(枚举、计数、复制等)

  • 支持序列化与反序列化


三、内部数据结构

1. 节点结构:LinkedListNode<T>

csharp 复制代码
public sealed class LinkedListNode<T>
{
    public T Value { get; set; }
    public LinkedListNode<T>? Next { get; }
    public LinkedListNode<T>? Previous { get; }
    public LinkedList<T>? List { get; }
}

特点:

  • 每个节点同时保存:

    • 当前值 Value
    • 前驱节点 Previous
    • 后继节点 Next
  • 节点与链表实例绑定,不能在多个链表之间共享


2. 链表整体结构

  • 维护:

    • 头节点 First
    • 尾节点 Last
    • 元素数量 Count
  • 内部逻辑结构为 首尾相连的双向循环链表(实现细节)


四、核心属性

属性 说明
First 获取第一个节点
Last 获取最后一个节点
Count 元素数量
csharp 复制代码
LinkedList<int> list = new LinkedList<int>();
LinkedListNode<int>? first = list.First;

五、核心方法分类

1. 添加元素

基于值的添加

csharp 复制代码
AddFirst(T value)
AddLast(T value)

基于节点的添加

csharp 复制代码
AddBefore(LinkedListNode<T> node, T value)
AddAfter(LinkedListNode<T> node, T value)

示例

csharp 复制代码
var list = new LinkedList<int>();
var node = list.AddLast(10);
list.AddAfter(node, 20);

2. 删除元素

csharp 复制代码
Remove(T value)
Remove(LinkedListNode<T> node)
RemoveFirst()
RemoveLast()
Clear()

注意事项:

  • Remove(T value) 删除的是第一个匹配项
  • 删除节点操作为 O(1)(前提是已持有节点引用)

3. 查找元素

csharp 复制代码
Find(T value)
FindLast(T value)
  • 返回 LinkedListNode<T>?
  • 查找时间复杂度为 O(n)

4. 枚举遍历

csharp 复制代码
foreach (var item in list)
{
    // 顺序遍历
}
  • 遍历顺序:从 FirstLast
  • 枚举期间修改集合会抛出 InvalidOperationException

六、时间与空间复杂度分析

操作 时间复杂度
头/尾插入 O(1)
已知节点插入 O(1)
已知节点删除 O(1)
查找 O(n)
遍历 O(n)

空间开销

  • 每个节点额外维护两个引用(PreviousNext
  • 相比数组型集合,内存占用更高

七、使用规范与注意事项

1. 何时应使用 LinkedList<T>

适用场景:

  • 频繁插入和删除
  • 操作对象是"节点位置",而非索引
  • 需要在遍历过程中进行结构修改

2. 不适合的场景

不推荐用于:

  • 高频随机访问
  • 仅进行尾部追加(List<T> 性能更优)
  • 数据量较小且结构简单的集合

3. 节点使用规范

❌ 错误示例(跨链表使用节点):

csharp 复制代码
var list1 = new LinkedList<int>();
var list2 = new LinkedList<int>();
var node = list1.AddLast(1);
list2.AddLast(node); // 抛异常

✅ 正确做法:

  • 每个 LinkedListNode<T> 只能属于一个链表

八、与 List<T> 的关键差异

维度 LinkedList List
底层结构 双向链表 动态数组
随机访问 不支持 支持
插入删除 高效 中间位置代价高
内存占用 较高 较低
常用性 较低 非常高

九、设计层面的总结

  • LinkedList<T>面向节点操作的集合

  • 其价值在于:

    • 常量时间的结构性修改
    • 明确的前驱 / 后继关系
  • 在现代 .NET 应用中属于特定场景下的工具型集合,而非通用首选

相关推荐
测试_AI_一辰2 小时前
Agent & RAG 测试工程 02:RAG 从最小闭环到可信
开发语言·前端·人工智能·github·ai编程
tudficdew2 小时前
C++中的策略模式实战
开发语言·c++·算法
naruto_lnq2 小时前
实时语音处理库
开发语言·c++·算法
程序员良辰2 小时前
JDK 环境变量的核心作用 ? 如果使用 IDEA 运行程序,是否可以不配置环境变量 ?
java·开发语言·intellij-idea
独自破碎E2 小时前
【数组】分糖果问题
java·开发语言·算法
charlie1145141912 小时前
现代嵌入式 C++——自定义删除器(Custom Deleter)
开发语言·c++·笔记·学习·嵌入式
闲谈共视2 小时前
Go语言与区块链技术的渊源
开发语言·golang·区块链
yaoxin5211232 小时前
305. Java Stream API - 短路操作
java·开发语言
程序员敲代码吗2 小时前
C++与硬件交互编程
开发语言·c++·算法