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

C#核心学习(三)常见的泛型数据结构类(1)List和Dictionary

        前面我们刚刚学习了,什么是泛型。今天我们就来看看C#中有哪些,常见的泛型数据结构,今天要介绍的是List,和Dictionary。

引言

        在C#编程中,泛型集合是高效管理数据的核心工具。List<T>Dictionary<TKey, TValue>作为两种最常用的泛型数据结构,分别解决了动态数组管理和键值对快速查找的核心需求。List<T>以动态扩容和有序存储为特点,支持灵活的索引操作和批量处理;Dictionary<TKey, TValue>则基于哈希表实现,通过唯一键实现近乎瞬时的数据检索。理解它们的特性、方法及适用场景,是提升代码性能和可维护性的关键。本文将系统解析这两种集合的核心功能、API及实践技巧,帮助开发者合理选择工具,优化数据处理逻辑。

1. List<T>(动态数组)

        前面我们有了静态数组,还有一个可以自动扩容的数组ArrayList,今天我们学习一个更加泛华的动态数组

List是一个C#为我们封装好的类
它的本质是一个可变类型的泛型数组
List类帮助我们实现了很多方法
比如泛型数组的增删查改

特性
  • 动态大小:自动调整容量以容纳新增元素。

  • 有序集合:元素按插入顺序存储,支持索引访问(如 list[0])。

  • 允许重复元素

  • 基于数组实现:支持快速随机访问(时间复杂度为 O(1))。

申明一个List出来:

注意:需要引入命名空间:using System.Collections.Generic;

// 空列表
List<int> numbers = new List<int>();
List<string> names = new List<string>();// 带初始容量(优化性能)
List<double> values = new List<double>(100);// 初始化时添加元素
List<char> chars = new List<char> { 'a', 'b', 'c' };
常用方法

添加元素

list.Add(item);      // 添加到末尾
list.Insert(index, item); // 插入到指定位置

增加也可以添加一个列表进去:利用AddRange

List<string> liststr = new List<string>();
list2.AddRange(liststr);

删除元素

list.Remove(item);   // 删除第一个匹配项
list.RemoveAt(index); // 删除指定索引的元素
list.Clear();        // 清空所有元素

查找元素

bool exists = list.Contains(item); // 检查是否存在
int index = list.IndexOf(item);    // 获取元素索引

关于查找:

        查找索引:

        IndexOf(T item)
        返回第一个匹配项的索引,未找到返回 -1。 

int index = list.IndexOf("apple");

  LastIndexOf(T item)
        返回最后一个匹配项的索引。 

int lastIndex = list.LastIndexOf("apple");

  FindIndex(Predicate<T> match)
根据条件查找第一个匹配项的索引。

int index = list.FindIndex(x => x.StartsWith("A"));

   FindLastIndex(Predicate<T> match)
根据条件查找最后一个匹配项的索引。 

int lastIndex = list.FindLastIndex(x => x > 100);

   BinarySearch(T item)
使用二分查找(要求列表已排序),返回索引或负数(未找到)。

list.Sort();
int index = list.BinarySearch("apple");

  Exists(Predicate<T> match)
检查是否存在符合条件的元素。

bool exists = list.Exists(x => x == 42);

容量管理: 

list.Capacity = 100; // 预分配容量(减少扩容次数)

遍历相关:

使用迭代器(foreach

foreach (int num in numbers)
{Console.WriteLine(num);
}

 不使用迭代器(for循环)

for (int i = 0; i < numbers.Count; i++)
{Console.WriteLine(numbers[i]);
}
性能
  • 添加/删除末尾元素:均摊 O(1)(自动扩容时可能需要复制数组)。

  • 插入/删除中间元素:O(n)(需移动后续元素)。

  • 查找元素:O(n)(需要遍历)。

注意事项
  • 预分配容量:若已知元素数量,初始化时指定容量(如 new List<int>(100))可减少扩容开销。

  • 避免频繁中间操作:频繁插入或删除中间元素时,性能较差。

2. Dictionary<TKey, TValue>(哈希表)

         字典,也称哈希表。就是存储着一对一对的值,和先前我们学习的普通哈希表差不多,只是可以自己定义类型

可以将Dictionary看作是一个键值对的集合,拥有泛型的HashTable
他也是基于键的哈希代码组织起来的键值对
键值对类型从HashTable的object变为了可以自己制定的泛型

特性
  • 键值对存储:每个键唯一对应一个值。

  • 无序集合:元素的顺序不固定(但遍历时顺序一致)。

  • 基于哈希表实现:通过哈希函数快速定位键。

  • 键不可重复:添加重复键会抛出异常。

申明一个字典出来:

注意:需要引用System.Collections.Generic

// 空字典
Dictionary<int, string> idToName = new Dictionary<int, string>();
Dictionary<string, float> productPrices = new Dictionary<string, float>();// 初始化时添加键值对
Dictionary<string, int> wordCounts = new Dictionary<string, int>
{{"apple", 5},{"banana", 3}
};
常用方法

添加/更新键值对

dict.Add(key, value); // 添加(键必须唯一)
dict[key] = value;    // 添加或覆盖

删除键值对: 

注意:删除键值对,只用删除键即可

dict.Remove(key);

查找操作

bool hasKey = dict.ContainsKey(key); // 检查键是否存在
bool hasValue = dict.ContainsValue(100);//检查是否值存在
bool success = dict.TryGetValue(key, out value); // 安全获取值
if (dict.TryGetValue("apple", out int count)) { /* ... */ }

遍历相关;

使用迭代器(遍历键值对)

foreach (KeyValuePair<string, int> pair in wordCounts)
{Console.WriteLine($"Key: {pair.Key}, Value: {pair.Value}");
}

遍历键或值

这里当你不确定类型的时候,建议使用var代替,系统自动判别

foreach (string key in wordCounts.Keys)
{Console.WriteLine(key);
}foreach (int value in wordCounts.Values)
{Console.WriteLine(value);
}

 不使用迭代器(通过集合转换)

var keys = wordCounts.Keys.ToList();
for (int i = 0; i < keys.Count; i++)
{string key = keys[i];Console.WriteLine(key);
}

 

性能
  • 添加/删除/查找:平均 O(1)(哈希冲突时可能退化为 O(n))。

  • 哈希函数质量:键的 GetHashCode() 应均匀分布以减少冲突。

注意事项
  • 键的不可变性:若键是可变对象(如自定义类),修改后会导致哈希值变化,无法定位原有值。

  • 自定义键类型:需正确实现 GetHashCode() 和 Equals() 方法。

  • 线程不安全:多线程操作需同步。

3. List vs Dictionary 对比

特性List<T>Dictionary<TKey, TValue>
存储方式有序元素集合键值对(键唯一)
查找性能O(n)(线性遍历)O(1)(哈希查找)
插入/删除性能末尾操作:O(1);中间操作:O(n)平均 O(1)
适用场景需要顺序访问或索引操作快速通过键查找值

4、总结

List<T> 的API及属性
类别方法/属性说明返回值/示例
声明与初始化List<T>()创建空列表List<int> list = new List<int>();
List<T>(int capacity)创建具有初始容量的列表List<string> list = new List<string>(100);
添加元素Add(T item)添加元素到列表末尾list.Add(10);
Insert(int index, T item)在指定索引插入元素list.Insert(0, "A");
删除元素Remove(T item)删除第一个匹配的元素list.Remove("apple");
RemoveAt(int index)删除指定索引的元素list.RemoveAt(0);
Clear()清空列表list.Clear();
查找索引IndexOf(T item)返回第一个匹配项的索引(未找到返回-1)int index = list.IndexOf(5);
LastIndexOf(T item)返回最后一个匹配项的索引int lastIndex = list.LastIndexOf(5);
FindIndex(Predicate<T> match)返回第一个符合条件的元素的索引int index = list.FindIndex(x => x > 10);
FindLastIndex(Predicate<T> match)返回最后一个符合条件的元素的索引int lastIndex = list.FindLastIndex(...);
其他操作Sort()对列表排序(默认升序)list.Sort();
BinarySearch(T item)二分查找(列表需已排序)int pos = list.BinarySearch(5);
Exists(Predicate<T> match)检查是否存在符合条件的元素bool exists = list.Exists(x => x == 0);
属性Count列表中的元素数量int count = list.Count;
Capacity列表的当前容量(可手动设置优化性能)list.Capacity = 100;
类别方法/属性说明示例
添加元素AddRange(IEnumerable<T> collection)批量添加集合元素到末尾list.AddRange(new[] { 4, 5, 6 });
插入元素InsertRange(int index, IEnumerable<T> collection)在指定位置插入集合元素list.InsertRange(0, new[] { -1, 0 });
删除元素RemoveRange(int index, int count)删除从索引 index 开始的 count 个元素list.RemoveRange(2, 3);
获取子集GetRange(int index, int count)返回从索引 index 开始的 count 个元素的子列表(浅拷贝)var sub = list.GetRange(1, 2);
排序与反转Reverse(int index, int count)反转指定范围的元素顺序list.Reverse(0, 3);
Dictionary<TKey, TValue> 的API及属性
类别方法/属性说明返回值/示例
声明与初始化Dictionary<TKey, TValue>()创建空字典Dictionary<int, string> dict = new ...;
添加/更新Add(TKey key, TValue value)添加键值对(键必须唯一,否则抛出异常)dict.Add(1, "A");
dict[key] = value添加或更新键对应的值dict[2] = "B";
删除元素Remove(TKey key)删除指定键的键值对dict.Remove(1);
Clear()清空字典dict.Clear();
查找操作ContainsKey(TKey key)检查键是否存在bool exists = dict.ContainsKey(1);
TryGetValue(TKey key, out TValue value)安全获取值(避免重复哈希计算)if (dict.TryGetValue(1, out string val))
ContainsValue(TValue value)检查值是否存在(时间复杂度O(n))bool hasVal = dict.ContainsValue("A");
属性Keys获取所有键的集合foreach (var key in dict.Keys) { ... }
Values获取所有值的集合foreach (var val in dict.Values) { ... }
Count字典中键值对的数量int count = dict.Count;
其他方法ElementAt(int index) (需Linq)按插入顺序获取指定位置的键值对(性能较差)var pair = dict.ElementAt(0);

 差不多常用的就这些了,你如果还想继续深入了解,可以去看官方文档。

相关文章:

  • DDoS(分布式拒绝服务)攻击
  • RNN - 循环神经网络(概念介绍)
  • 通过额外的磁盘挂载进行扩容(win与linux空间共享)——linux最多也就推荐100G
  • ZEP: 一种用于智能体记忆的时序知识图谱架构
  • C#设计模式-状态模式
  • Rust-引用借用规则
  • MyBatis持久层框架
  • 开源模型集成接口
  • C# 运行web项目
  • Maven 编译指定模版
  • Aosp13 文件应用点击apk无反应的处理
  • 日常学习开发记录-slider组件
  • Rocky Linux 9.x 基于 kubeadm部署k8s
  • 基于Tesseract与Opencv的电子发票识别[1]
  • Vue 人看 React useRef:它不只是替代 ref
  • cocos 3D自由世界游戏 - 开发
  • GitHub实用手册
  • Java项目之基于ssm的学校小卖部收银系统(源码+文档)
  • 获取 arm-none-eabi-ld 默认使用的链接脚本
  • 【2-10】E1与T1
  • 国家医保局副局长颜清辉调任人社部副部长
  • 违规行为屡禁不止、责任边界模糊不清,法治日报:洞穴探险,谁为安全事故买单?
  • 中信银行一季度净利195.09亿增1.66%,不良率持平
  • 五一“拼假”催热超长假期,热门酒店民宿一房难求
  • 中方发布《不跪!》视频传递何种信息?外交部回应
  • 日趋活跃!2024年我国数据生产总量同比增长25%