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

发布于:2025-04-16 ⋅ 阅读:(32) ⋅ 点赞:(0)

        前面我们刚刚学习了,什么是泛型。今天我们就来看看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);

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


网站公告

今日签到

点亮在社区的每一天
去签到