c# List ,Dictionary,HashSet,Stack,Queue

1. List 集合 : 一种可以存储对象的列表,可以通过索引访问其中的元素, 和数组不同,数组一旦定义后,必须指定长度,List可以动态的增加大小。List 内部使用数组存储,如果满了,将创建一个新的更大的数组,并将现有的数组中的项目复制到新的数组中。
创建集合: var list = new List<string>();
集合常用方法:
添加元素 : list.Add("tom");
在某个索引位置插入元素: list.Insert("jack",0);
删除某个元素: list.Remove("jack");
根据索引删除元素: list.Remove(0);
根据索引获取某个元素:var item = list[0];
获取某个元素的索引: list.IndexOf("tom");
获取集合中元素的个数: list.Count;
判断集合是否包含某个元素: var contains = list.Contains("mary");
集合遍历: foreach (var item in list) { Console.WriteLine(item); }
在开头或中间添加/删除元素
如果你在list的开头或者中间添加或者删除一个元素,它需要移动一个或者多个其它元素。如果是在开头添加或者删除一个元素,那么所有的元素都需要移动,元素越多,越耗性能。如果用大O表示执行成本,为O(n)。这意味着,算法的执行时间和n是线性关系,即元素的个数越多,执行此操作的成本越高。
在集合的末尾添加/删除元素
在list的末尾添加/删除一个元素是一个相对快速的操作,并且不取决于list的大小。现有的元素不需要移动。这个操作的成本是相对固定的,和list中元素的个数没有关系。用大O符号来表示这个操作的执行成本为 O(1). 1在这里意味着常数。
查找元素
当我们使用如 IndexOf,Contains,Find等方法查找某个元素时,需要从list的头部开始向尾部一个个查找,直到找到匹配的元素后返回,这个操作的成本也是线性的,O(n),最差的情况是,所要查找的元素位于list的最后一个,这种情况下成本最高。
根据索引查找元素
list的优势之处在于,无论list有多大都可以通过索引快速查找到对应的元素,这个操作的时间复杂度为 O(1)
总结
list 通过索引查找元素是很快的,时间复杂度为O(1),如果不想基于索引查找元素,则可以使用接下来要介绍的字典(Dictionary)

2.Dictionary<Tkey,TValue> (字典)
字典是一种键值对集合的数据类型,可以通过键(TKey),快速的找到对应的值(TValue)。
键必须是唯一的,而值不需要唯一的
键和值都可以是任何类型(比如:string, int, 自定义类型,等等)
例如,如果你有一些客户的数据,而你想通过客户的ID快速找到对应的客户信息,如果使用上面介绍的list,那么你需要一个个遍历,直到找到对应的客户,最坏的情况是要查找的客户位于list末尾,那样成本是很高的,时间复杂度为O(n),而如果使用字典,则可以通过ID,快速找到对应的客户,时间复杂度为O(1),也就是说无论字典多大,查询的时间是相对固定的。
创建字典var dictionary = new Dictionary<int, Customer>(); ,此处key为int类型,Value为Customer
查找元素:通过ID(12)查找客户 var customer = dictionary[12];
通过key删除元素: dictionary.Remove(12);
清空字典dictionary.Clear();
添加元素dictionary.Add(customer.Id, customer); 也可以在字典初始化时添加,如下

var dictionary = new Dictionary<int, Customer>
               {
                    { customer1.Id, customer1 },
                    { customer2.Id, customer2 }
               }

常见方法

var count = dictionary.Count; 

var containsKey = dictionary.ContainsKey(1);
 
var containsValue = dictionary.ContainsValue(customer1);
 
// 通过Key遍历
foreach (var key in dictionary.Keys)
     Console.WriteLine(dictionary[key]);
 
// 通过值遍历
foreach (var value in dictionary.Values)
     Console.WriteLine(value);
 
// 通过键值对遍历
foreach (var keyValuePair in dictionary)
{
     Console.WriteLine(keyValuePair.Key);
     Console.WriteLine(keyValuePair.Value);
}

原理: 字典的内部也是一个数组,但是和list 直接在末尾添加元素,(或者通过索引添加)不同的是,字典的索引是通过哈希函数计算而来的,当我们往字典中添加一个元素时,它会通过key值调用GetHashCode 方法计算得出哈希值,然后再根据得到的哈希值通过对字典的长度进行取余得到索引值,再存放Value值。在数组中通过索引查找值,时间复杂度为O(1),因此在字典中查找元素,不需要像list那样从头扫描遍历元素,直到找到为止,这也是为啥字典查找快的原因。

3.HashSet
HashSet 是一个存放唯一元素的集合,即里面存放的元素不能重复。元素的顺序不相关,所以 {1,2,3} 和{3,2,1} 是相等的。HashSet,类似于Dictionary,是一个基于哈希的集合,所以查找的速度非常快,为O(1)。但与字典不同,它不存储键/值对;它只存储值。
常见用法

// 创建并初始化
  var hashSet = new HashSet<int>() { 1, 2, 3 };
 // 添加元素
 hashSet.Add(4);
  
 // 删除元素
 HashSet. Remove(3);
  
 // 删除所有元素
 hashSet.Clear();
  
 // 判断是否包含某个元素
 var contains = hashSet.Contains(1);
  
 // 获取元素的个数
 var count = hashSet.Count;

4.Stack 堆栈
堆栈是一种后进先出(LIFO)的集合类型。我们经常在需要为用户提供返回方式的情况下使用堆栈。比如当你浏览不同的网站时,你访问的这些地址被推到一个堆栈上。然后,当你点击返回按钮时,堆栈上的元素(代表浏览器中的当前地址)被弹出,我们可以从堆栈上的项目中得到你最后访问的地址。应用程序中的撤销功能也是用堆栈实现的。
使用方法

 var stack = new Stack<string>();
          
 // 往堆栈中压入元素
 stack.Push("http://www.baidu.com");
  
 // 判断是否包含某个元素。 复杂度为 O(n)
 var contains = stack.Contains("http://www.baidu.com");
  
 // 将栈顶元素出栈(删除),并返回这个元素
 var top = stack.Pop();
  
 // 将栈顶元素出栈(不删除),并返回这个元素 
 var top = stack.Peek();
  
 // 获取元素的个数
 var count = stack.Count;
  
 //删除所有元素
 stack.Clear();

堆栈是基于数组来实现的。由于数组有一个固定的大小,当你把项目推入堆栈时,它可能需要通过重新分配一个更大的数组并把现有的项目复制到新的数组中来增加其容量。如果不需要重新分配,推送操作复杂度为O(1);否则,如果需要重新分配,假设堆栈有n个元素,所有这些元素都需要被复制到新的数组中。这导致了运行时复杂度为O(n)。

5.Queue
队列表示一个具有先进先出(FIFO)行为的集合。当我们需要根据它们的先后顺序处理它们时,就可以采用队列。例如 抢购下单请求的处理。

Enqueue:将一个元素添加到队列的末端
Dequeue:移除队列前端的元素
Peek:检查前面的元素,但不删除它。
常见用法

  var queue = new Queue<string>();

  // 往队列中添加元素
  queue.Enqueue("transaction1");
   
  // 检测队列是否包含某个元素
  var contains = queue.Contains("transaction1");
   
  // 返回对列头部的元素,并从队列中删除它
  var front = queue.Dequeue();
   
  // 返回对列头部的元素,不把它从队列中删除
  var top = queue.Peek();
               
  // 删除队列中所有的元素
  queue.Clear();
   
  // 获取队列元素的个数
  var count = queue.Count;

总结
1.当你需要通过索引访问一个元素时,使用list查找速度很快,但是在list中搜索一个元素时是缓慢的,因为它需要线性搜索。
2.字典提供了通过键进行快速查找的功能。键应该是唯一的,并且不能是空的。
3.当你需要快速查找一个元素是否存在于一个集合中时,HashSet很有用。由于HashSet中元素无序的问题,即{1,2,3}和{3,2,1}等价,所以千万不要去遍历它。
4.由于堆栈后进先出的特性,当你想为用户提供某些回退操作的时候,使用堆栈很合适。
5.处理像订单抢购等场景时,需要先到达先处理,使用队列(先进先出)最合适。

posted @ 2021-06-13 10:58  反方向的钟lld  阅读(505)  评论(0编辑  收藏  举报