当前位置: 首页 > 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…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

python报错No module named ‘tensorflow.keras‘

是由于不同版本的tensorflow下的keras所在的路径不同&#xff0c;结合所安装的tensorflow的目录结构修改from语句即可。 原语句&#xff1a; from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后&#xff1a; from tensorflow.python.keras.lay…...