当前位置: 首页 > news >正文

【C#知识点详解】LinkedList<T>储存结构详解

        今天来介绍一下LinkedList<T>的内部结构,说不多说直接开始。

内部数据

        LinkedList是一个双向链表结构的容器,其内部为非连续的内存空间。LinkedList包含的主要成员示例如下:

//起始LinkedListNode节点
internal LinkedListNode<T>? head;
//LinkedList中包含的数据数量
internal int count;
//版本号,用于检测LinkedList是否被修改
internal int version;

public sealed class LinkedListNode<T>
{
	// 存储的数据对象
	internal T item;	
	//下一个LinkedListNode节点
    internal LinkedListNode<T>? next;	
	//上一个LinkedListNode节点
    internal LinkedListNode<T>? prev;
}

        LinkedListNodeLinkedList中一个重要的数据结构,其中包含了三个成员变量:

  • T item:数据对象,item是实际存储数据的地方。
  • LinkedListNode<T>? next:指向下一个LinkedListNode的节点,没有则为null。
  • LinkedListNode<T>? prev:指向上一个LinkedListNode的节点,没有则为null。

        LinkedListNode<T>? head存储的是起始LinkedListNode节点。

        int count记录的是LinkedList中存储数据的数量。

        int version记录的是版本号信息,用于检测LinkedList是否被修改,每次LinkedList修改时version会加1处理。

数据操作

        添加数据

        LinkedList有多种添加数据的方式,方法如下:

  • AddFirst(T value):在列表头部添加数据。
  • AddLast(T value):在列表尾部添加数据。
  • AddAfter(LinkedListNode<T> node, T value):在指定节点前面添加数据。
  • AddBefore(LinkedListNode<T> node, T value):在指定节点后面添加数据。

        添加数据的过程为先创建一个新的LinkedListNode对象,然后根据不同的方法,将LinkedListNode对象插入到指定节点的前面或者后面。这里以AddLast举例,示例代码如下:

public LinkedListNode<T> AddLast(T value)
{
    LinkedListNode<T> result = new LinkedListNode<T>(this, value);
    if (head == null)
    {
        InternalInsertNodeToEmptyList(result);
    }
    else
    {
        InternalInsertNodeBefore(head, result);
    }
    return result;
}

private void InternalInsertNodeBefore(LinkedListNode<T> node, LinkedListNode<T> newNode)
{
    newNode.next = node;
    newNode.prev = node.prev;
    node.prev!.next = newNode;
    node.prev = newNode;
    version++;
    count++;
}

        这里讲解一下InternalInsertNodeBefore方法,由于LinkedList是双向链表,在调用AddLast方法在尾部添加数据时,newNode.next的下一个节点也就是head节点,head的上一个节点会被设置为newNode.prev对象。略微有点绕,不过简单推导一下基本可以理解。

        移除数据

        LinkedList同样有多种移除数据的方法,示例如下:

  • Remove(T value):移除指定数据对象,当存在多个相同数据时,会移除第一个相同的数据。
  • Remove(LinkedListNode<T> node):移除指定节点。
  • RemoveFirst():移除第一个节点。
  • RemoveLast():移除最后一个节点。

        几个方法移除数据的过程基本相同,这里以Remove(T value)示例,示例代码如下:

public bool Remove(T value)
{
    LinkedListNode<T>? node = Find(value);
    if (node != null)
    {
        InternalRemoveNode(node);
        return true;
    }
    return false;
}

internal void InternalRemoveNode(LinkedListNode<T> node)
{
    if (node.next == node)
    {
        head = null;
    }
    else
    {
        node.next!.prev = node.prev;
        node.prev!.next = node.next;
        if (head == node)
        {
            head = node.next;
        }
    }
    node.Invalidate();
    count--;
    version++;
}

        移除数据的主要过程在InternalRemoveNode(LinkedListNode<T> node)方法中,其主要操作是将移除对象的前后节点进行重行赋值,小伙伴可以自己推导一下。

        遍历数据

        先来介绍一下用foreach遍历LinkedList,foreach是从头到尾逐个遍历LinkedList。需要注意的是遍历过程中不能对LinkedList进行插入/删除操作,不然会抛出异常。示例代码如下:

LinkedList<string> list = new LinkedList<string>();
// 添加元素...

foreach (string item in list)
{
    Console.WriteLine(item);
}

        其次是用for循环遍历LinkedList,for循环的好处在于可以正向遍历,也可以反向遍历,并且在遍历过程中可以对LinkedList进行插入/删除操作。示例代码如下:

// 正向遍历
for (LinkedListNode<string> node = list.First; node != null; node = node.Next)
{
    Console.WriteLine(node.Value);
}

// 反向遍历
for (LinkedListNode<string> node = list.Last; node != null; node = node.Previous)
{
    Console.WriteLine(node.Value);
}

相关文档链接

LinkedList<T> 类官方文档:https://learn.microsoft.com/zh-cn/dotnet/api/system.collections.generic.linkedlist-1?view=net-9.0

LinkedList源码地址:https://github.com/dotnet/runtime/blob/main/src/libraries/System.Collections/src/System/Collections/Generic/LinkedList.cs

相关文章:

  • Spring Boot接口返回Long类型的数据时丢失精度的全局处理
  • LCR 131. 砍竹子 I
  • 什么是混合搜索Hybrid Search?
  • Python 小练习系列 | Vol.14:掌握偏函数 partial,用函数更丝滑!
  • 和DeepSeek聊高速公路定向广播
  • NO.79十六届蓝桥杯备战|数据结构-扩展域并查集-带权并查集|团伙|食物链|银河英雄传说(C++)
  • CesiumEarth v1.12 更新,支持安卓平板离线浏览3DTiles格式的三维倾斜模型
  • 【计网】作业4
  • 树和图论(详细整理,简单易懂!)
  • AutoGLM沉思使用方式
  • 【已完结STM32】--自学江协科技笔记汇总
  • WHAT - React 元素接收的 ref 详解
  • 最新Spring Security实战教程(九)前后端分离认证实战 - JWT+SpringSecurity无缝整合
  • 进程间通信-共享内存
  • 辛格迪客户案例 | 河南宏途食品实施电子合约系统(eSign)
  • Wideband Sparse Reconstruction for Scanning Radar论文阅读
  • Linux网络配置与测试
  • 鸿蒙小案例-京东登录
  • 记录IBM服务器检测到备份GPT损坏警告排查解决过程
  • 信息系统项目管理师-第十四章-项目沟通管理
  • 央行:全力推进一揽子金融政策加快落地
  • 李云泽:再批复600亿元,进一步扩大保险资金长期投资试点范围
  • 习近平致电祝贺默茨当选德国联邦总理
  • 城事|五一长假,哪里人最多?
  • 科技日报刊文批院士专家“赶场式”跑会:助长浮躁之气功利之心
  • 俄军击落多架企图攻击莫斯科的无人机