Array数组
内存上连续存储,
数组是引用类型而不是值类型。
优点:
按照索引查询元素速度很快。
按照索引遍历数组很方便。
缺点:
声明数组时大小必须确定,且大小不能改变。
添加和删除元素的速度很慢,因为需要移动其它元素。
数组只能存储一种数据类型。
一维数组的声明和创建形式:
数组类型 [ ] 数组名 = new 数组类型 [数组长度]
如 int [ ] one = new int [5] { 1, 2, 3, 4, 5 };
相当于MFC 的CArray
二维数组
int [,] one = new int [2,3];
位数组 BitArray
ArrayList
ArrayList类相当于一种高级的动态数组,它是Array类的升级版本.本质是一个object类型的数组.ArrayList类是引用类型。连续的内存。在存和使用值类型的对象时或发生装箱/拆箱的操作。
using System .Collections ;
ArrayList List=new ArrayList();
ArrayList 转Array的函数
Array ToArray(Type type);
ArrayList List = new ArrayList();
for (int i = 0; i < 10; i++)
List.Add(i);
int[] values = (int[])List.ToArray(typeof(int)); //正确
List
List<T> 等效于ArrayList,性能比Arraylist高。 List的内部是用数组实现的,而不是链表,所以也是连续内存。当元素被添加到List中时,List的容量会根据需要自动增加,通过重新分配内部数组。
List<int> primeNumbers = new List<int>();
List 转Array的函数
List<int> primeNumbers = new List<int>();
for (int i = 0; i < 10; i++)
primeNumbers.Add(i);
int[] Numbers = primeNumbers.ToArray();
Array转 List 的函数
int [] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ,10};
List<int > list = new List<int >(array);
相当于 c++ 的vector
LinkedList(双向链表)
内存非连续的、非顺序的存储结构,无法通过下标查找元素,在查找链表元素时,总是从头结点开始查找;动态调整容量。
查询复杂度为 O(n),操作复杂度为 O(1)。
遍历:
LinkedListNode<int> nowNode=linkedList.First;
while(nowNode!=null)
{
nowNode=nowNode.Next;
}
或者
foreach(int item in linkedList)
{
Console.WriteLine(item);
}
Array转Linked List 的函数
int [] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ,10};
LinkedList<int > linkedList = new LinkedList<int >(array);
相当于c++的 list
Stack(栈)
栈是有顺序的,是一片连续的内存域,保持着先进后出的原则。
Stack<string> numbers = new Stack<string>();
numbers.Push("one");
string str = numbers.Peek(); //获取不出栈
str = numbers.Pop();//获取并出栈
Queue(队列)
先进先出,存在装箱拆箱,存储任意类型,无法获取指定位置元素,只能取出最先存储的元素。
Queue<string> queue = new Queue<string>();
//向队列中添加元素
ueue.Enqueue ("老一");
queue.Enqueue ("老二");
queue.Dequeue ();获取并移除队列中队首的元素
queue.Peek ();返回顶部的对象而不将其从 队列 中移除
HashSet
是基于哈希表的原理实现的,根据key直接访问存储位置的数据结构
无序、不重复;
插入、查找时间复杂度为O(1);
不使用索引;
容量不足时自动扩容,但扩容成本高;
HashSet<string> hashSet = new HashSet<string>();
hashSet.Add ("123");
hashSet.Add ("456");
//转换成List集合
hashSet.ToList();
相当于STL 的hash_set或者说unordered_set
SortedSet
基于红黑树实现,有序、不重复的集合
SortedSet<string> SortSet = new SortedSet<string>();
SortSet.Add ("123");
hashSet.Add ("456");
foreach (var index in SortSet)
{
}
//转换成List集合
SortSet.ToList();
相当于STL的set
Hashtable
基于哈希表实现,一系列基于键的哈希代码组织起来的 键/值对 。它使用键来访问集合中的元素。
特点:
key(键) 是唯一的,不可重复,
只能通过 key 查询对应 的value
Hashtable hashtable = new Hashtable();
hashtable.Add(0, 1);
hashtable.Add(1, 'a');
foreach (var key in hashtable.Keys)
{
var tablekey = key;
var value = hashtable[key];
}
相当于STL 的unordered_map (hash_map)
Dictionary(字典)
基于哈希表实现,字典中的key值是唯一的。
字典底层将数据储存在数组里面,通过哈希函数建立Key------Value的对应关系,利用拉链法处理哈希冲突。另外,字典是线程不安全的,如果需要线程安全,需要自己加锁
Dictionary<int, string> _testDic = new Dictionary<int, string>();
_testDic.Add (24, "Canon");
// 注意相同相同Key值只能Add一次
_testDic.Add (34, "Jason"); // foreach遍历
foreach (var kvp in _testDic)
{
Console .WriteLine ("Key = {0}, Value = {1}", kvp.Key , kvp.Value );
}
相当于STL 的unordered_map (hash_map)
Dictionary和Hashtable对比
Dictionary<K,V>是泛型的,当K或V是值类型时,其速度远远超过Hashtable。
由于 Hashtable 和 Dictionary 同时存在, 在使用场景上必然存在选择性, 并不任何时刻都能相互替代.
[1] 单线程程序中推荐使用 Dictionary, 有泛型优势, 且读取速度较快, 容量利用更充分.
[2] 多线程程序中推荐使用 Hashtable, 默认的 Hashtable 允许单线程写入, 多线程读取, 对 Hashtable 进一步调用 Synchronized() 方法可以获得完全线程安全的类型. 而 Dictionary 非线程安全, 必须人为使用 lock 语句进行保护, 效率大减.
[3] Dictionary 有按插入顺序排列数据的特性 (注: 但当调用 Remove() 删除过节点后顺序被打乱), 因此在需要体现顺序的情境中使用 Dictionary 能获得一定方便.
SortedDictionary
基于使用红黑树实现的键值对集合。
特点:
有序,键唯一
只能通过 key(键) 查询对应 的 value(值)
SortedDictionary 可对未排序的数据执行更快的插入和移除操作:它的时间复杂度为 O(log n)
SortedDictionary<int, string> My_sdict = new SortedDictionary<int, string>();
My_sdict.Add (004, "Ask.com");
My_sdict.Add (003, "Yahoo");
foreach (var kvp in My_sdict)
{
Console .WriteLine ("Key = {0}, Value = {1}", kvp.Key , kvp.Value );
}
相当于STL的map
SortedList
排序列表是数组和哈希表的组合,使用索引访问各项,则它是一个动态数组,如果您使用键访问各项,则它是一个哈希表。集合中的各项总是按键值排序。
总结
数据结构 类型及备注 插入和删除 查找
Array 顺序存储的线性表、定长 不支持(这里的插入与删除指会更改表长的行为) O(N)
LinkedList<T> 链式存储的线性表、不定长 O(1) O(N)
List<T> 顺序存储的线性表、不定长、动态扩容 O(N),结尾则是O(1) O(N)
Stack<T> 栈、不定长、动态扩容 O(1) 只能访问栈顶
Queue<T> 队列、不定长、动态扩容 O(1) 只能访问队列头部
Dictionary<K,T> 保存键值对、使用开散列法、不定长、动态扩容、长度总为质数 O(1) O(1)
SortedList<K,T> 保存键值对、内部使用数组实现、保持有序、不定长 O(logN) O(logN)
SortedDictionary<K,T> 保存键值对、内部使用红黑树实现、保持有序、不定长 O(logN) O(logN)
HashSet<K> 使用开散列法、不定长、动态扩容、长度总为质数、是不含值的字典,故复杂度和它完全相同 O(1) O(1)
SortedSet<T> 内部使用红黑树实现、保持有序、不定长、是不含值的SortedDictionary<K,T>,故复杂度和它完全相同 O(logN) O(logN)