C#集合类是程序开发中必不可少的工具,用于存储和管理数据。集合类提供了丰富的数据结构和算法,帮助开发者高效地操作数据。本文将深入探讨C#中的集合类,从基本概念到高级用法,全面解析集合类的原理和机制,并结合实际案例,帮助读者掌握集合类的精髓。

集合类的基本概念

集合类的意义

集合类用于存储和管理一组数据,提供了数据的添加、删除、查询、排序等操作。集合类在程序开发中有着广泛的应用,通过集合类,开发者可以高效地处理大量数据,简化代码,提高程序的性能和可维护性。

集合类的分类

C#中的集合类主要分为以下几类:

  1. 数组(Array):固定大小的元素序列。
  2. 列表(List):动态大小的元素序列。
  3. 链表(LinkedList):元素之间通过节点链接的序列。
  4. 集合(Set):不包含重复元素的集合。
  5. 字典(Dictionary):键值对的集合。
  6. 队列(Queue):先进先出(FIFO)原则的集合。
  7. 栈(Stack):后进先出(LIFO)原则的集合。

数组(Array)

数组的基本概念

数组是固定大小的元素序列,所有元素类型相同。数组通过索引访问元素,索引从0开始。数组在内存中是连续存储的,访问速度快,但插入和删除操作效率低。

  1. public class Program
  2. {
  3. public static void Main(string[] args)
  4. {
  5. int[] numbers = new int[5];
  6. for (int i = 0; i < numbers.Length; i++)
  7. {
  8. numbers[i] = i + 1;
  9. }
  10. foreach (int number in numbers)
  11. {
  12. Console.WriteLine(number);
  13. }
  14. }
  15. }

在这个例子中,我们定义了一个大小为5的整数数组,并对数组元素进行初始化和遍历。

多维数组

C#支持多维数组,用于存储二维或多维数据。常见的多维数组包括矩阵(二维数组)和立方体(三维数组)。

  1. public class Program
  2. {
  3. public static void Main(string[] args)
  4. {
  5. int[,] matrix = new int[3, 3];
  6. for (int i = 0; i < matrix.GetLength(0); i++)
  7. {
  8. for (int j = 0; j < matrix.GetLength(1); j++)
  9. {
  10. matrix[i, j] = i * matrix.GetLength(1) + j + 1;
  11. }
  12. }
  13. for (int i = 0; i < matrix.GetLength(0); i++)
  14. {
  15. for (int j = 0; j < matrix.GetLength(1); j++)
  16. {
  17. Console.Write($"{matrix[i, j]} ");
  18. }
  19. Console.WriteLine();
  20. }
  21. }
  22. }

在这个例子中,我们定义了一个3x3的二维数组,并对数组元素进行初始化和遍历。

交错数组

交错数组是数组的数组,每个子数组的大小可以不同。交错数组提供了更灵活的数据存储方式。

  1. public class Program
  2. {
  3. public static void Main(string[] args)
  4. {
  5. int[][] jaggedArray = new int[3][];
  6. jaggedArray[0] = new int[] { 1, 2, 3 };
  7. jaggedArray[1] = new int[] { 4, 5 };
  8. jaggedArray[2] = new int[] { 6, 7, 8, 9 };
  9. foreach (int[] subArray in jaggedArray)
  10. {
  11. foreach (int number in subArray)
  12. {
  13. Console.Write($"{number} ");
  14. }
  15. Console.WriteLine();
  16. }
  17. }
  18. }

在这个例子中,我们定义了一个交错数组,每个子数组的大小不同,并对数组元素进行初始化和遍历。

列表(List)

列表的基本概念

列表是动态大小的元素序列,所有元素类型相同。列表通过索引访问元素,支持动态添加和删除元素。列表在内存中是连续存储的,访问速度快,插入和删除操作效率较高。

  1. using System;
  2. using System.Collections.Generic;
  3. public class Program
  4. {
  5. public static void Main(string[] args)
  6. {
  7. List<int> numbers = new List<int>();
  8. for (int i = 0; i < 5; i++)
  9. {
  10. numbers.Add(i + 1);
  11. }
  12. foreach (int number in numbers)
  13. {
  14. Console.WriteLine(number);
  15. }
  16. }
  17. }

在这个例子中,我们定义了一个整数列表,并对列表元素进行初始化和遍历。

列表的常用方法

列表提供了丰富的方法,用于操作列表元素。常用方法包括AddRemoveInsertIndexOfContains等。

  1. using System;
  2. using System.Collections.Generic;
  3. public class Program
  4. {
  5. public static void Main(string[] args)
  6. {
  7. List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
  8. // 添加元素
  9. numbers.Add(6);
  10. // 删除元素
  11. numbers.Remove(3);
  12. // 插入元素
  13. numbers.Insert(2, 10);
  14. // 查找元素索引
  15. int index = numbers.IndexOf(4);
  16. // 判断是否包含元素
  17. bool contains = numbers.Contains(5);
  18. foreach (int number in numbers)
  19. {
  20. Console.WriteLine(number);
  21. }
  22. Console.WriteLine($"索引:{index}");
  23. Console.WriteLine($"包含元素:{contains}");
  24. }
  25. }

在这个例子中,我们演示了列表的常用方法,包括添加、删除、插入、查找和判断元素。

链表(LinkedList)

链表的基本概念

链表是元素之间通过节点链接的序列,支持动态添加和删除元素。链表分为单向链表和双向链表,单向链表的节点只包含下一个节点的引用,双向链表的节点包含前一个和下一个节点的引用。

  1. using System;
  2. using System.Collections.Generic;
  3. public class Program
  4. {
  5. public static void Main(string[] args)
  6. {
  7. LinkedList<int> numbers = new LinkedList<int>();
  8. numbers.AddLast(1);
  9. numbers.AddLast(2);
  10. numbers.AddLast(3);
  11. foreach (int number in numbers)
  12. {
  13. Console.WriteLine(number);
  14. }
  15. }
  16. }

在这个例子中,我们定义了一个整数链表,并对链表元素进行初始化和遍历。

链表的常用方法

链表提供了丰富的方法,用于操作链表元素。常用方法包括AddFirstAddLastRemoveFindAddBeforeAddAfter等。

  1. using System;
  2. using System.Collections.Generic;
  3. public class Program
  4. {
  5. public static void Main(string[] args)
  6. {
  7. LinkedList<int> numbers = new LinkedList<int>();
  8. numbers.AddLast(1);
  9. numbers.AddLast(2);
  10. numbers.AddLast(3);
  11. // 在链表头部添加元素
  12. numbers.AddFirst(0);
  13. // 在链表尾部添加元素
  14. numbers.AddLast(4);
  15. // 删除元素
  16. numbers.Remove(2);
  17. // 查找元素
  18. LinkedListNode<int> node = numbers.Find(3);
  19. // 在指定节点前添加元素
  20. numbers.AddBefore(node, 2);
  21. // 在指定节点后添加元素
  22. numbers.AddAfter(node, 5);
  23. foreach (int number in numbers)
  24. {
  25. Console.WriteLine(number);
  26. }
  27. }
  28. }

在这个例子中,我们演示了链表的常用方法,包括在链表头部和尾部添加元素、删除元素、查找元素以及在指定节点前后添加元素。

集合(Set)

集合的基本概念

集合是不包含重复元素的集合,所有元素类型相同。集合通过哈希表实现,提供快速的元素添加、删除和查找操作。常用的集合类包括HashSetSortedSet

  1. using System;
  2. using System.Collections.Generic;
  3. public class Program
  4. {
  5. public static void Main(string[] args)
  6. {
  7. HashSet<int> numbers = new HashSet<int> { 1, 2, 3, 4, 5 };
  8. // 添加元素
  9. numbers.Add(6);
  10. // 删除元素
  11. numbers.Remove(3);
  12. // 判断是否包含元素
  13. bool contains = numbers.Contains(4);
  14. foreach (int number in numbers)
  15. {
  16. Console.WriteLine(number);
  17. }
  18. Console.WriteLine($"包含元素:{contains}");
  19. }
  20. }

在这个例子中,我们定义了一个整数集合,并对集合元素进行初始化、添加、删除和判断操作。

集合

的常用方法

集合提供了丰富的方法,用于操作集合元素。常用方法包括AddRemoveContainsUnionWithIntersectWithExceptWith等。

  1. using System;
  2. using System.Collections.Generic;
  3. public class Program
  4. {
  5. public static void Main(string[] args)
  6. {
  7. HashSet<int> set1 = new HashSet<int> { 1, 2, 3, 4, 5 };
  8. HashSet<int> set2 = new HashSet<int> { 4, 5, 6, 7, 8 };
  9. // 并集
  10. set1.UnionWith(set2);
  11. // 交集
  12. set1.IntersectWith(set2);
  13. // 差集
  14. set1.ExceptWith(set2);
  15. foreach (int number in set1)
  16. {
  17. Console.WriteLine(number);
  18. }
  19. }
  20. }

在这个例子中,我们演示了集合的常用方法,包括并集、交集和差集操作。

字典(Dictionary)

字典的基本概念

字典是键值对的集合,每个键唯一对应一个值。字典通过哈希表实现,提供快速的键值对添加、删除和查找操作。常用的字典类包括DictionarySortedDictionary

  1. using System;
  2. using System.Collections.Generic;
  3. public class Program
  4. {
  5. public static void Main(string[] args)
  6. {
  7. Dictionary<int, string> dictionary = new Dictionary<int, string>
  8. {
  9. { 1, "One" },
  10. { 2, "Two" },
  11. { 3, "Three" }
  12. };
  13. // 添加键值对
  14. dictionary[4] = "Four";
  15. // 删除键值对
  16. dictionary.Remove(2);
  17. // 查找值
  18. string value = dictionary[3];
  19. // 判断是否包含键
  20. bool contains = dictionary.ContainsKey(4);
  21. foreach (KeyValuePair<int, string> kvp in dictionary)
  22. {
  23. Console.WriteLine($"{kvp.Key}: {kvp.Value}");
  24. }
  25. Console.WriteLine($"值:{value}");
  26. Console.WriteLine($"包含键:{contains}");
  27. }
  28. }

在这个例子中,我们定义了一个整数键和值的字典,并对字典元素进行初始化、添加、删除和查找操作。

字典的常用方法

字典提供了丰富的方法,用于操作字典元素。常用方法包括AddRemoveTryGetValueContainsKeyContainsValue等。

  1. using System;
  2. using System.Collections.Generic;
  3. public class Program
  4. {
  5. public static void Main(string[] args)
  6. {
  7. Dictionary<int, string> dictionary = new Dictionary<int, string>
  8. {
  9. { 1, "One" },
  10. { 2, "Two" },
  11. { 3, "Three" }
  12. };
  13. // 添加键值对
  14. dictionary.Add(4, "Four");
  15. // 删除键值对
  16. dictionary.Remove(2);
  17. // 尝试获取值
  18. if (dictionary.TryGetValue(3, out string value))
  19. {
  20. Console.WriteLine($"值:{value}");
  21. }
  22. // 判断是否包含键
  23. bool containsKey = dictionary.ContainsKey(4);
  24. // 判断是否包含值
  25. bool containsValue = dictionary.ContainsValue("Four");
  26. foreach (KeyValuePair<int, string> kvp in dictionary)
  27. {
  28. Console.WriteLine($"{kvp.Key}: {kvp.Value}");
  29. }
  30. Console.WriteLine($"包含键:{containsKey}");
  31. Console.WriteLine($"包含值:{containsValue}");
  32. }
  33. }

在这个例子中,我们演示了字典的常用方法,包括添加、删除、查找和判断键值对。

队列(Queue)

队列的基本概念

队列是先进先出(FIFO)原则的集合,元素按照添加的顺序排列。队列支持在队尾添加元素,在队头移除元素。常用的队列类包括QueueConcurrentQueue

  1. using System;
  2. using System.Collections.Generic;
  3. public class Program
  4. {
  5. public static void Main(string[] args)
  6. {
  7. Queue<int> queue = new Queue<int>();
  8. queue.Enqueue(1);
  9. queue.Enqueue(2);
  10. queue.Enqueue(3);
  11. // 移除元素
  12. int first = queue.Dequeue();
  13. // 获取队头元素但不移除
  14. int peek = queue.Peek();
  15. foreach (int number in queue)
  16. {
  17. Console.WriteLine(number);
  18. }
  19. Console.WriteLine($"移除元素:{first}");
  20. Console.WriteLine($"队头元素:{peek}");
  21. }
  22. }

在这个例子中,我们定义了一个整数队列,并对队列元素进行初始化、添加、移除和获取操作。

队列的常用方法

队列提供了丰富的方法,用于操作队列元素。常用方法包括EnqueueDequeuePeekContainsClear等。

  1. using System;
  2. using System.Collections.Generic;
  3. public class Program
  4. {
  5. public static void Main(string[] args)
  6. {
  7. Queue<int> queue = new Queue<int>();
  8. queue.Enqueue(1);
  9. queue.Enqueue(2);
  10. queue.Enqueue(3);
  11. // 判断是否包含元素
  12. bool contains = queue.Contains(2);
  13. // 清空队列
  14. queue.Clear();
  15. foreach (int number in queue)
  16. {
  17. Console.WriteLine(number);
  18. }
  19. Console.WriteLine($"包含元素:{contains}");
  20. Console.WriteLine($"队列是否为空:{queue.Count == 0}");
  21. }
  22. }

在这个例子中,我们演示了队列的常用方法,包括添加、判断和清空队列元素。

栈(Stack)

栈的基本概念

栈是后进先出(LIFO)原则的集合,元素按照添加的顺序排列。栈支持在栈顶添加元素,在栈顶移除元素。常用的栈类包括StackConcurrentStack

  1. using System;
  2. using System.Collections.Generic;
  3. public class Program
  4. {
  5. public static void Main(string[] args)
  6. {
  7. Stack<int> stack = new Stack<int>();
  8. stack.Push(1);
  9. stack.Push(2);
  10. stack.Push(3);
  11. // 移除元素
  12. int top = stack.Pop();
  13. // 获取栈顶元素但不移除
  14. int peek = stack.Peek();
  15. foreach (int number in stack)
  16. {
  17. Console.WriteLine(number);
  18. }
  19. Console.WriteLine($"移除元素:{top}");
  20. Console.WriteLine($"栈顶元素:{peek}");
  21. }
  22. }

在这个例子中,我们定义了一个整数栈,并对栈元素进行初始化、添加、移除和获取操作。

栈的常用方法

栈提供了丰富的方法,用于操作栈元素。常用方法包括PushPopPeekContainsClear等。

  1. using System;
  2. using System.Collections.Generic;
  3. public class Program
  4. {
  5. public static void Main(string[] args)
  6. {
  7. Stack<int> stack = new Stack<int>();
  8. stack.Push(1);
  9. stack.Push(2);
  10. stack.Push(3);
  11. // 判断是否包含元素
  12. bool contains = stack.Contains(2);
  13. // 清空栈
  14. stack.Clear();
  15. foreach (int number in stack)
  16. {
  17. Console.WriteLine(number);
  18. }
  19. Console.WriteLine($"包含元素:{contains}");
  20. Console.WriteLine($"栈是否为空:{stack.Count == 0}");
  21. }
  22. }

在这个例子中,我们演示了栈的常用方法,包括添加、判断和清空栈元素。

泛型集合与非泛型集合

泛型集合

泛型集合是指使用泛型定义的集合类,提供类型安全的集合操作。常用的泛型集合类包括List<T>LinkedList<T>HashSet<T>Dictionary<TKey, TValue>Queue<T>Stack<T>等。

  1. using System;
  2. using System.Collections.Generic;
  3. public class Program
  4. {
  5. public static void Main(string[] args)
  6. {
  7. List<int> list = new List<int> { 1, 2, 3, 4, 5 };
  8. Dictionary<int, string> dictionary = new Dictionary<int, string>
  9. {
  10. { 1, "One" },
  11. { 2, "Two" },
  12. { 3, "Three" }
  13. };
  14. foreach (int number in list)
  15. {
  16. Console.WriteLine(number);
  17. }
  18. foreach (KeyValuePair<int, string> kvp in dictionary)
  19. {
  20. Console.WriteLine($"{kvp.Key}: {kvp.Value}");
  21. }
  22. }
  23. }

在这个例子中,我们演示了泛型集合List<T>Dictionary<TKey, TValue>的使用。

非泛型集合

非泛型集合是指不使用泛型定义的集合类,操作时需要进行类型转换。常用的非泛型集合类包括ArrayListHashtableQueueStack等。

  1. using System;
  2. using System.Collections;
  3. public class Program
  4. {
  5. public static void Main(string[] args)
  6. {
  7. ArrayList list = new ArrayList { 1, 2, 3, 4, 5 };
  8. Hashtable hashtable = new Hashtable
  9. {
  10. { 1, "One" },
  11. { 2, "Two" },
  12. { 3, "Three" }
  13. };
  14. foreach (int number in list)
  15. {
  16. Console.WriteLine(number);
  17. }
  18. foreach (DictionaryEntry entry in hashtable)
  19. {
  20. Console.WriteLine($"{entry.Key}: {entry.Value}");
  21. }
  22. }
  23. }

在这个例子中,我们演示了非泛型集合ArrayListHashtable的使用。

并发集合

并发集合的基本概念

并发集合是用于在多线程环境下安全地操作集合数据的集合类。并发集合提供线程安全的添加、删除和查找操作,常用的并发集合类包括ConcurrentDictionaryConcurrentBagConcurrentQueueConcurrentStack等。

  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Threading.Tasks;
  4. public class Program
  5. {
  6. public static void Main(string[] args)
  7. {
  8. ConcurrentDictionary<int, string> dictionary = new ConcurrentDictionary<int, string>();
  9. // 添加键值对
  10. dictionary[1] = "One";
  11. dictionary[2] = "Two";
  12. // 并发添加键值对
  13. Parallel.For(0, 10, i =>
  14. {
  15. dictionary[i] = $"Value{i}";
  16. });
  17. foreach (KeyValuePair<int, string> kvp in dictionary)
  18. {
  19. Console.WriteLine($"{kvp.Key}: {kvp.Value}");
  20. }
  21. }
  22. }

在这个例子中,我们演示了并发集合ConcurrentDictionary的使用,包括在多线程环境下并发添加键值对。

并发集合的常用方法

并发集合提供了丰富的方法,用于操作集合元素。常用方法包括TryAddTryRemoveTryGetValueAddOrUpdateGetOrAdd等。

  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Threading.Tasks;
  4. public class Program
  5. {
  6. public static void Main(string[] args)
  7. {
  8. ConcurrentDictionary<int, string> dictionary = new ConcurrentDictionary<int, string>();
  9. // 尝试添加键值对
  10. bool added = dictionary.TryAdd(1, "One");
  11. // 尝试删除键值对
  12. bool removed = dictionary.TryRemove(1, out string removedValue);
  13. // 尝试获取值
  14. bool gotValue = dictionary.TryGetValue(1, out string value);
  15. // 添加或更新键值对
  16. string updatedValue = dictionary.AddOrUpdate(1, "One", (key, oldValue) => oldValue + "Updated");
  17. // 获取或添加键值对
  18. string gotOrAddedValue = dictionary.GetOrAdd(1, "One");
  19. Console.WriteLine($"添加键值对:{added}");
  20. Console.WriteLine($"删除键值对:{removed}");
  21. Console.WriteLine($"获取值:{gotValue}");
  22. Console.WriteLine($"添加或更新键值对:{updatedValue}");
  23. Console.WriteLine($"获取或添加键值对:{gotOrAddedValue}");
  24. }
  25. }

在这个例子中,我们演示了并发集合ConcurrentDictionary的常用方法,包括尝试添加、删除、获取、更新和添加键值对。

集合的性能优化

集合的选择

选择合适的集合类对于程序的性能优化至关重要。在选择集合类时,应根据数据的特点和操作的需求,选择适合的数据结构。例如,对于需要快速查找和删除元素的场景,可以选择哈希表或字典;对于需要顺序访问和动态添加元素的场景,可以选择列表或链表。

  1. using System;
  2. using System.Collections.Generic;
  3. public class Program
  4. {
  5. public static void Main(string[] args)
  6. {
  7. // 需要快速查找和删除元素
  8. Dictionary<int, string> dictionary = new Dictionary<int, string>();
  9. dictionary[1] = "One";
  10. dictionary[2] = "Two";
  11. Console.WriteLine(dictionary[1]);
  12. // 需要顺序访问和动态添加元素
  13. List<int> list = new List<int> { 1, 2, 3, 4, 5 };
  14. list.Add(6);
  15. foreach (int number in list)
  16. {
  17. Console.WriteLine(number);
  18. }
  19. }
  20. }

在这个例子中,我们根据不同的需求选择了合适的集合类,提高了程序的性能。

集合的容量管理

对于动态大小的集合类,如ListDictionary,可以通过预先设置容量来提高性能,减少内存分配和复制操作的开销。

  1. using System;
  2. using System.Collections.Generic;
  3. public class Program
  4. {
  5. public static void Main(string[] args)
  6. {
  7. // 设置初始容量
  8. List<int> list = new List<int>(100);
  9. for (int i = 0; i < 100; i++)
  10. {
  11. list.Add(i + 1);
  12. }
  13. Dictionary<int, string> dictionary = new Dictionary<int, string>(100);
  14. for (int i = 0; i < 100; i++)
  15. {
  16. dictionary[i] = $"Value{i}";
  17. }
  18. Console.WriteLine("集合初始化完成");
  19. }
  20. }

在这个例子中,我们通过预先设置集合的初始容量,提高了集合的性能。

集合的并发操作

在多线程环境下,使用并发集合类可以提高集合的操作性能,避免线程竞争和锁竞争。

  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Threading.Tasks;
  4. public class Program
  5. {
  6. public static void Main(string[] args)
  7. {
  8. ConcurrentBag<int> bag = new ConcurrentBag<int>();
  9. // 并发添加元素
  10. Parallel.For(0, 100, i =>
  11. {
  12. bag.Add(i);
  13. });
  14. Console.WriteLine("并发添加元素完成");
  15. // 并发移除元素
  16. Parallel.For(0, 100, i =>
  17. {
  18. if (bag.TryTake(out int value))
  19. {
  20. Console.WriteLine($"移除元素:{value}");
  21. }
  22. });
  23. Console.WriteLine("并发移除元素完成");
  24. }
  25. }

在这个例子中,我们使用并发集合ConcurrentBag在多线程环境下进行并发添加和移除元素,提高了集合的操作性能。

总结

集合类是C#编程中的一个重要方面,通过数组、列表、链表、集合、字典、队列、栈等集合类,开发者可以高效地存储和管理数据。本文深入探讨了C#中的集合类,从基本概念到高级用法,全面解析了集合类的原理和机制,并结合实际案例展示了集合类在各种场景中的应用。

掌握集合类不仅能够提高代码的健壮性和性能,还能够在复杂应用程序中发挥重要作用。希望本文能帮助读者更好地理解和掌握C#中的集合类,在实际开发中充分利用这一强大的编程工具。通过对集合类的深入理解和合理应用,可以编写出更加高效、可靠和稳定的程序。