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

C#中List<T>底层原理剖析

C#中List底层原理剖析

  • 1. 基础用法
  • 2. List的Capacity与Count:
  • 3.List的底层原理
    • 3.1. 构造
    • 3.2 Add()接口
    • 3.3 Remove()接口
    • 3.4 Inster()接口
    • 3.5 Clear()接口
    • 3.6 Contains()接口
    • 3.7 ToArray()接口
    • 3.8 Find()接口
    • 3.8 Sort()接口
  • 4. 总结
  • 5. 参考

人物

1. 基础用法

list.Max() 取最大元素

list.Avgage() 取平均值

static void Main()
{List<string> names = new List<string>();names.Add("一号元素");names.Add("二号元素");names.Add("狗");names[2] = "三号元素";//修改第三个元素string[] str = new string[] { "四号元素", "五号元素", "六号元素" };names.AddRange(str);//为集合增加数组Console.WriteLine("当前集合元素个数为{0}",names.Count);//返回集合元素个数Console.WriteLine("当前集合的容量为{0}", names.Capacity);//返回当前集合的容量//当添加元素的时候集合的容量不足以容纳所有元素就会自动增加目前元素数一倍的容量。Console.WriteLine(names.Contains("三号元素"));//返回集合中是否存在某元素,bool类型names.IndexOf("三号元素");//返回元素的索引值names.Clear();//清空所有元素,元素个数为0,但是容量不变
}

2. List的Capacity与Count:

  • Count 属性表示 List 中实际包含的元素数量。它是一个只读属性。
  • Capacity 属性表示 List 内部数组的容量,即它可以容纳的元素的数量。容量是指分配给列表的内部数组的大小,而不是列表中实际包含的元素数量。
  • 当添加元素时,如果内部数组的容量不够,List 会自动调整容量以容纳更多的元素。
List<int> list1= new List<int>();
WriteLine($"List的初始容量:{list1.Capacity}"); 
WriteLine($"List的初始数量:{list1.Count}");
list1.Add(0);
WriteLine($"通过Add()添加一个元素后的容量:{list1.Capacity}");
WriteLine($"通过Add()添加一个元素后的数量:{list1.Count}");

以上代码输出:

List的初始容量:0
List的初始数量:0
通过Add()添加一个元素后的容量:4
通过Add()添加一个元素后的数量:1

3.List的底层原理

3.1. 构造

private class List<T> : Ilist<T>, System.Collections.IList, IReadOnlyList<T>

List内部是由数组实现的,当没有指定额定容量时,初始容量为0。

3.2 Add()接口

将给定对象添加到此列表的末尾。每次增加元素前,都会判断数组容量是否够。不够则进行扩容

public void Add(T item)
  • 每次扩容都会扩充一倍。数组初始值为0,扩容初始值为4,因此整个扩容路线是:0-4-8-16-32-64-125-256……
  • 每次扩容都会申请新的空间,然后进行元素拷贝,然后还要回收旧空间。会给GC造成不小的负担。
  • 另外还有浪费空间的缺点。比如存放126个元素时,会扩容到256的空间,剩下的130个空间就浪费了。

3.3 Remove()接口

删除列表中首次出现的item。将从头到尾搜索,使用Object.Equal()进行相等的判断。

public bool Remove(T item)
  • 找到要删除的位置后,使用Array.Copy()进行覆盖;
  • 时间复杂度O(n);
  • 删除一个元素后,内部数组的容量不变。

3.4 Inster()接口

功能:在给定索引处插入元素。每次插入元素前都会检查当前容量是否足够,如果不够则进行扩容。

public void Insert(int index, T item);
  • 在插入元素时,采用的也是复制数组的形式,将数组指定索引后面的元素向后移动一个位置。
  • 与Add()类似,会给GC产生负担,并且存在空间浪费的问题。

3.5 Clear()接口

功能:清除列表内容。注意:只是将Count置,之前申请空间不变,也就是Capacity不变。

List<int> list1= new List<int>();
list1.Add(0);
WriteLine($"通过Add()添加一个元素后的容量:{list1.Capacity}"); 
WriteLine($"通过Add()添加一个元素后的数量:{list1.Count}");
list1.Clear();
WriteLine($"Clear后的容量:{list1.Capacity}"); //清除后容量不变。即之前申请的空间不变
WriteLine($"Clear后的数量:{list1.Count}"); //数量置0

以上输出:

通过Add()添加一个元素后的容量:4
通过Add()添加一个元素后的数量:1
Clear后的容量:4
Clear后的数量:0

3.6 Contains()接口

功能:确定某元素是否在List中。

public bool Contains(T item)
  • 使用线性查找的方式,挨个比较元素。

3.7 ToArray()接口

复制列表到一个新数组,O(n)的操作。

public T[] ToArray()

3.8 Find()接口

功能:查找满足指定条件的元素。接受一个Predicate委托作为参数,该委托定义了要应用于每个元素的条件。

public T Find(Predicate<T> match)
  • 线性查找的方式,挨个比较,返回满足条件的第一个元素。
  • 用法:
    List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
    // 使用Find函数查找大于3的第一个元素
    int result = numbers.Find(x => x > 3); //Lambda表达式x => x > 3表示条件
    Console.WriteLine(result);  // 输出: 4
    

3.8 Sort()接口

功能:对列表中的元素进行排序。Sort 方法使用元素的默认比较器进行排序,或者可以传递一个自定义的比较器作为参数。

public void Sort(int index, int count, TComparee<T> comparer)
  • index与count是指定排序区间。不指定的话则整个列表进行排序;
  • 用法
    List<int> numbers = new List<int> { 5, 2, 8, 1, 3 };
    numbers.Sort();
    numbers.Sort((x, y) => y.CompareTo(x));// 使用自定义比较器对列表进行降序排序
    
  • 该方法在原地修改列表,而不是返回排序后的列表。
  • 排序时使用Array.Sort()方法进行排序,该方法内部采用了快速排序,效率是O(nlogn).

4. 总结

  1. List的效率并不高,甚至比数组还差,只是通用性强而已;
  2. List 的内存分配方式也不合理。当List 里的元素不断增加时,会多次重新分配数组,导致原来的数组被抛弃,造成回收的压力。
  3. 对于第2点的问题,我们可以在创建List 实例时提前告知 List 对象最多会有多少元素在里面,这样 List 就不会因为空间不够而抛弃原有的数组去重新申请教组了。例如:
    List<int> list11 = new List<int>(128);
    WriteLine($"容量:{list11.Capacity}"); //容量:128
    WriteLine($"数量:{list11.Count}"); //数量:0
    
  4. List是线程不安全的。
    • 当多个线程同时访问和修改同一个 List 实例时,可能会导致不可预测的结果或发生错误。
    • 例如,并发读写的问题。一个线程正在读取列表的元素,而另一个线程在同时修改列表,这可能导致读取到无效或不正确的数据。
    • 可使用同步机制解决该问题。lock语句或其他同步机制来保护对 List 的并发访问。确保同一时间只有一个线程访问列表。

5. 参考

List源码地址:链接: https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs

相关文章:

C#中List<T>底层原理剖析

C#中List底层原理剖析 1. 基础用法2. List的Capacity与Count&#xff1a;3.List的底层原理3.1. 构造3.2 Add()接口3.3 Remove()接口3.4 Inster()接口3.5 Clear()接口3.6 Contains()接口3.7 ToArray()接口3.8 Find()接口3.8 Sort()接口 4. 总结5. 参考 1. 基础用法 list.Max() …...

Leetcode 3003. Maximize the Number of Partitions After Operations

Leetcode 3003. Maximize the Number of Partitions After Operations 1. 解题思路2. 代码实现 题目链接&#xff1a;10038. Maximize the Number of Partitions After Operations 1. 解题思路 这一题我看实际比赛当中只有72个人做出来&#xff0c;把我吓得够呛&#xff0c;…...

MySQL第一讲:MySQL知识体系详解(P6精通)

MySQL知识体系详解(P6精通) MySQL不论在实践还是面试中,都是频率最高的。本系列主要对MySQL知识体系梳理,将给大家构建JVM核心知识点全局知识体系,本文是MySQL第一讲,MySQL知识体系详解。 文章目录 MySQL知识体系详解(P6精通)1、MySQL学习建议1.1、为什么学习 MySQL?1.2、…...

逻辑回归简单案例分析--鸢尾花数据集

文章目录 1. IRIS数据集介绍2. 具体步骤2.1 手动将数据转化为numpy矩阵2.1.1 从csv文件数据构建Numpy数据2.1.2 模型的搭建与训练2.1.3 分类器评估2.1.4 分类器的分类报告总结2.1.5 用交叉验证&#xff08;Cross Validation&#xff09;来验证分类器性能2.1.6 完整代码&#xf…...

Python print 高阶玩法

Python print 高阶玩法 当涉及到在Python中使用print函数时&#xff0c;有许多方式可以玩转文本样式、字体和颜色。在此将深入探讨这些主题&#xff0c;并介绍一些print函数的高级用法。 1. 基本的文本样式与颜色设置 使用ANSI转义码 ANSI转义码是一种用于在终端&#xff0…...

Wpf 使用 Prism 实战开发Day09

设置模块设计 1.效果图 一.系统设置模块&#xff0c;主要有个性化(用于更改主题颜色)&#xff0c;系统设置&#xff0c;关于更多&#xff0c;3个功能点。 个性化的颜色内容样式&#xff0c;主要是从 Material Design Themes UI简称md、提供的demo里复制代码过来使用的。 1.设置…...

网络端口(包括TCP端口和UDP端口)的作用、定义、分类,以及在视频监控和流媒体通信中的定义

目 录 一、什么地方会用到网络端口&#xff1f; 二、端口的定义和作用 &#xff08;一&#xff09;TCP协议和UDP协议 &#xff08;二&#xff09;端口的定义 &#xff08;三&#xff09;在TCP/IP体系中&#xff0c;端口(TCP和UDP)的作用 &#xff08;…...

flink如何写入es

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、写入到Elasticsearch5二、写入到Elasticsearch7总结 前言 Flink sink 流数据写入到es5和es7的简单示例。 一、写入到Elasticsearch5 pom maven依赖 <d…...

Java、Python、C++和C#的界面开发框架和工具的重新介绍

好的&#xff0c;以下是Java、Python、C和C#的界面开发框架和工具的重新介绍&#xff1a; Java界面开发&#xff1a; Swing: 是Java提供的一个基于组件的GUI工具包&#xff0c;可以创建跨平台的图形用户界面。它提供了丰富的组件和布局管理器&#xff0c;使得界面开发相对简单。…...

Java二叉树的遍历以及最大深度问题

Java学习面试指南&#xff1a;https://javaxiaobear.cn 1、树的相关概念 1、树的基本定义 树是我们计算机中非常重要的一种数据结构&#xff0c;同时使用树这种数据结构&#xff0c;可以描述现实生活中的很多事物&#xff0c;例如家谱、单位的组织架构、等等。 树是由n&#…...

Apollo 9.0搭建问题记录

虚拟机安装 可以看这个&#xff1a;https://blog.csdn.net/qq_45138078/article/details/129815408 写的很详细 内存 为了学习 Apollo &#xff0c;所以只是使用了虚拟机&#xff0c;内存得大一点&#xff08;128G&#xff09;&#xff0c;第一次&#xff0c;就是因为分配内…...

【心得】PHP文件包含高级利用攻击面个人笔记

目录 一、nginx日志文件包含 二、临时文件包含 三、php的session文件包含 四、pear文件包含 五 、远程文件包含 文件包含 include "/var/www/html/flag.php"; 一 文件名可控 $file$_GET[file]; include $file.".php"; //用php伪协议 &#xff0…...

[scala] 列表常见用法

文章目录 不可变列表 List可变列表 ListBuffer 不可变列表 List 在 Scala 中&#xff0c;列表是一种不可变的数据结构&#xff0c;用于存储一系列元素。列表使用 List 类来表示&#xff0c;它提供了许多方法来操作和处理列表。 下面是一些常见的使用列表的示例&#xff1a; 创…...

python 使用urllib3发起post请求,携带json参数

当通过python脚本&#xff0c;发起http post请求&#xff0c;网络上大多是通过fields传递数据&#xff0c;然而这样&#xff0c;服务器收到的请求&#xff0c;但无法解析json数据。类似这些链接&#xff1a; Python urllib3库使用指南 软件测试|Python urllib3库使用指南 p…...

深入理解堆(Heap):一个强大的数据结构

. 个人主页&#xff1a;晓风飞 专栏&#xff1a;数据结构|Linux|C语言 路漫漫其修远兮&#xff0c;吾将上下而求索 文章目录 前言堆的实现基本操作结构体定义初始化堆&#xff08;HeapInit&#xff09;销毁堆&#xff08;HeapDestroy&#xff09; 重要函数交换函数&#xff08;…...

抖音在线查权重系统源码,附带查询接口

抖音权重在线查询只需输入抖音主页链接&#xff0c;即可查询作品情况。 搭建教程 上传源码并解压 修改数据库“bygoukai.sql” 修改“config.php” 如需修改水印请修改第40行 如需修改限制次数&#xff0c;请修改第156行 访问域名user.php即可查看访问用户&#xff0c;停…...

Spring Framework和SpringBoot的区别

目录 一、前言 二、什么是Spring 三、什么是Spring Framework 四、什么是SpringBoot 五、使用Spring Framework构建工程 六、使用SpringBoot构建工程 七、总结 一、前言 作为Java程序员&#xff0c;我们都听说过Spring&#xff0c;也都使用过Spring的相关产品&#xff0…...

2024--Django平台开发-Django知识点(三)

day03 django知识点 项目相关路由相关 urls.py视图相关 views.py模版相关 templates资源相关 static/media 1.项目相关 新项目 开发时&#xff0c;可能遇到使用其他的版本。虚拟环境 老项目 打开项目虚拟环境 1.1 关于新项目 1.系统解释器命令行【学习】 C:/python38- p…...

Github 2024-01-08开源项目周报 Top14

根据Github Trendings的统计&#xff0c;本周(2024-01-08统计)共有14个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目5TypeScript项目3C项目2Dart项目1QML项目1Go项目1Shell项目1Rust项目1JavaScript项目1C#项目1 免费…...

vue3 的内置组件汇总

官方给出的说明&#xff1a; Fragment: Vue 3 组件不再要求有一个唯一的根节点&#xff0c;清除了很多无用的占位 div。Teleport: 允许组件渲染在别的元素内&#xff0c;主要开发弹窗组件的时候特别有用。Suspense: 异步组件&#xff0c;更方便开发有异步请求的组件。 一、fr…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

管理学院权限管理系统开发总结

文章目录 &#x1f393; 管理学院权限管理系统开发总结 - 现代化Web应用实践之路&#x1f4dd; 项目概述&#x1f3d7;️ 技术架构设计后端技术栈前端技术栈 &#x1f4a1; 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 &#x1f5c4;️ 数据库设…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用

文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么&#xff1f;1.1.2 感知机的工作原理 1.2 感知机的简单应用&#xff1a;基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...

JavaScript 数据类型详解

JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型&#xff08;Primitive&#xff09; 和 对象类型&#xff08;Object&#xff09; 两大类&#xff0c;共 8 种&#xff08;ES11&#xff09;&#xff1a; 一、原始类型&#xff08;7种&#xff09; 1. undefined 定…...

CSS | transition 和 transform的用处和区别

省流总结&#xff1a; transform用于变换/变形&#xff0c;transition是动画控制器 transform 用来对元素进行变形&#xff0c;常见的操作如下&#xff0c;它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

SQL Server 触发器调用存储过程实现发送 HTTP 请求

文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...

Unity中的transform.up

2025年6月8日&#xff0c;周日下午 在Unity中&#xff0c;transform.up是Transform组件的一个属性&#xff0c;表示游戏对象在世界空间中的“上”方向&#xff08;Y轴正方向&#xff09;&#xff0c;且会随对象旋转动态变化。以下是关键点解析&#xff1a; 基本定义 transfor…...