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 应用中属于特定场景下的工具型集合,而非通用首选

相关推荐
rockey6278 分钟前
AScript之eval函数详解
c#·.net·script·eval·expression·动态脚本
Alice-YUE35 分钟前
【js高频八股】防抖与节流
开发语言·前端·javascript·笔记·学习·ecmascript
云泽80839 分钟前
C++11 核心特性全解:列表初始化、右值引用与移动语义实战
开发语言·c++
froginwe111 小时前
DOM 加载函数
开发语言
Hello eveybody1 小时前
介绍一下背包DP(Python)
开发语言·python·动态规划·dp·背包dp
AI进化营-智能译站1 小时前
ROS2 C++开发系列12-用多态与虚函数构建可扩展的ROS2机器人行为模块
开发语言·c++·ai·机器人
iCxhust2 小时前
微机原理实践教程(C语言篇)---A002流水灯
c语言·开发语言·单片机·嵌入式硬件·51单片机·课程设计·微机原理
莎士比亚的文学花园2 小时前
Linux驱动开发(3)——设备树
开发语言·javascript·ecmascript
图码2 小时前
如何用多种方法判断字符串是否为回文?
开发语言·数据结构·c++·算法·阿里云·线性回归·数字雕刻
U盘失踪了2 小时前
python curl转python脚本
开发语言·chrome·python