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. 总结
- List的效率并不高,甚至比数组还差,只是通用性强而已;
- List 的内存分配方式也不合理。当List 里的元素不断增加时,会多次重新分配数组,导致原来的数组被抛弃,造成回收的压力。
- 对于第2点的问题,我们可以在创建List 实例时提前告知 List 对象最多会有多少元素在里面,这样 List 就不会因为空间不够而抛弃原有的数组去重新申请教组了。例如:
List<int> list11 = new List<int>(128); WriteLine($"容量:{list11.Capacity}"); //容量:128 WriteLine($"数量:{list11.Count}"); //数量:0
- 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: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. 代码实现 题目链接:10038. Maximize the Number of Partitions After Operations 1. 解题思路 这一题我看实际比赛当中只有72个人做出来,把我吓得够呛,…...
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 用交叉验证(Cross Validation)来验证分类器性能2.1.6 完整代码…...

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

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

网络端口(包括TCP端口和UDP端口)的作用、定义、分类,以及在视频监控和流媒体通信中的定义
目 录 一、什么地方会用到网络端口? 二、端口的定义和作用 (一)TCP协议和UDP协议 (二)端口的定义 (三)在TCP/IP体系中,端口(TCP和UDP)的作用 (…...
flink如何写入es
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、写入到Elasticsearch5二、写入到Elasticsearch7总结 前言 Flink sink 流数据写入到es5和es7的简单示例。 一、写入到Elasticsearch5 pom maven依赖 <d…...
Java、Python、C++和C#的界面开发框架和工具的重新介绍
好的,以下是Java、Python、C和C#的界面开发框架和工具的重新介绍: Java界面开发: Swing: 是Java提供的一个基于组件的GUI工具包,可以创建跨平台的图形用户界面。它提供了丰富的组件和布局管理器,使得界面开发相对简单。…...

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

Apollo 9.0搭建问题记录
虚拟机安装 可以看这个:https://blog.csdn.net/qq_45138078/article/details/129815408 写的很详细 内存 为了学习 Apollo ,所以只是使用了虚拟机,内存得大一点(128G),第一次,就是因为分配内…...

【心得】PHP文件包含高级利用攻击面个人笔记
目录 一、nginx日志文件包含 二、临时文件包含 三、php的session文件包含 四、pear文件包含 五 、远程文件包含 文件包含 include "/var/www/html/flag.php"; 一 文件名可控 $file$_GET[file]; include $file.".php"; //用php伪协议 ࿰…...
[scala] 列表常见用法
文章目录 不可变列表 List可变列表 ListBuffer 不可变列表 List 在 Scala 中,列表是一种不可变的数据结构,用于存储一系列元素。列表使用 List 类来表示,它提供了许多方法来操作和处理列表。 下面是一些常见的使用列表的示例: 创…...
python 使用urllib3发起post请求,携带json参数
当通过python脚本,发起http post请求,网络上大多是通过fields传递数据,然而这样,服务器收到的请求,但无法解析json数据。类似这些链接: Python urllib3库使用指南 软件测试|Python urllib3库使用指南 p…...

深入理解堆(Heap):一个强大的数据结构
. 个人主页:晓风飞 专栏:数据结构|Linux|C语言 路漫漫其修远兮,吾将上下而求索 文章目录 前言堆的实现基本操作结构体定义初始化堆(HeapInit)销毁堆(HeapDestroy) 重要函数交换函数(…...

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

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

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

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

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

网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...

12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
c# 局部函数 定义、功能与示例
C# 局部函数:定义、功能与示例 1. 定义与功能 局部函数(Local Function)是嵌套在另一个方法内部的私有方法,仅在包含它的方法内可见。 • 作用:封装仅用于当前方法的逻辑,避免污染类作用域,提升…...
DiscuzX3.5发帖json api
参考文章:PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下,适配我自己的需求 有一个站点存在多个采集站,我想通过主站拿标题,采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...

EEG-fNIRS联合成像在跨频率耦合研究中的创新应用
摘要 神经影像技术对医学科学产生了深远的影响,推动了许多神经系统疾病研究的进展并改善了其诊断方法。在此背景下,基于神经血管耦合现象的多模态神经影像方法,通过融合各自优势来提供有关大脑皮层神经活动的互补信息。在这里,本研…...