数组

数组是一种特殊类型的数据类型,它可以使用特殊语法顺序存储固定数量的值。

【C#基础】常用数据结构 - 图1

数组声明

  1. int [] intArr;

数组初始化:使用new关键字同时声明和初始化数组,下面三种方式等价

  1. int[] intArr = new int[5];
  2. int[] intArr = new int[5]{1 2 3 4 5};
  3. int[] intArr = {1 2 3 4 5};

延迟初始化:可以先声明后再初始化数组

  1. string[] strArr strArr;
  2. strArr = new string[5]{ "1st Element""2nd Element" "3rd Element"};
  3. strArr = new string[]{ "1st Element""2nd Element" "3rd Element"};

索引访问数组中元素

  1. intArr[索引位置];
方法名称 描述
GetLength(int维度) 返回指定维度中的元素数
GetLowerBound(int维度) 返回指定维度的最低索引
GetUpperBound(int维度) 返回指定维度的最高索引
GetValue(int index) 返回指定索引处的值
属性 描述
Length 返回数组中元素的总数
  1. // 数组可以先声明后赋值,也可以声明同时赋值,下面的方式是等价的,数组中必须存储同一类型数据,这在数组被定义时就已经确定
  2. // 第一种
  3. int[] intArr = new int[5];
  4. intArr[0] = 1;
  5. intArr[1] = 2;
  6. intArr[2] = 3;
  7. intArr[3] = 4;
  8. intArr[4] = 5;
  9. // 第二种
  10. //int[] intArr = new int[5] { 1, 2, 3, 4, 5 };
  11. // 第三种
  12. //int[] intArr = { 1, 2, 3, 4, 5 };
  13. // 注意这里是维度不是索引
  14. Console.WriteLine("GetLength(int维度):返回指定维度中的元素数,值为:{0}" intArr.GetLength(0));
  15. Console.WriteLine("GetLowerBound(int维度):返回指定维度的最低索引,值为:{0}" intArr.GetLowerBound(0));
  16. Console.WriteLine("GetUpperBound(int维度):返回指定维度的最高索引,值为:{0}" intArr.GetUpperBound(0));
  17. Console.WriteLine("GetValue(int index): 返回指定索引处的值,值为:{0}" intArr.GetValue(2));
  18. Console.WriteLine("属性:Length:返回数组中元素的总数,值为:{0}" intArr.Length);
  19. // 使用索引来访问数组元素
  20. Console.WriteLine("使用索引访问数组元素,索引为2的值为:{0}" intArr[2]);
  21. // 试图访问数组中不存在的索引元素,会发生数组越界
  22. Console.WriteLine("使用索引访问数组元素,索引为10的值为:{0}" intArr[10]);
  23. for (int i = 0; i < intArr.Length; i++)
  24. {
  25. Console.WriteLine(intArr[i]);
  26. }
  27. foreach (var item in intArr)
  28. {
  29. Console.WriteLine(item);
  30. }

多维数组

多维数组是行和列的二维系列。多维数组又称为矩形数组;在本质上,是个一维数组的列表。

  1. // 下面的两种创建方式等价
  2. // 第一种
  3. // int[,] intArray = { { 1, 1 }, { 1, 2 }, { 1, 3 } };
  4. // 第二种
  5. int[,] intArray = new int[3 4]{ //初始化化一个三行四列的数组
  6. {0 1 2 3} /* 初始化索引号为 0 的行 */
  7. {4 5 6 7} /* 初始化索引号为 1 的行 */
  8. {8 9 10 11} /* 初始化索引号为 2 的行 */
  9. };
  10. // 下面的语句将获取数组中第3行第4个元素
  11. Console.WriteLine("二维数组中的元素是通过使用下标(即数组的行索引和列索引)来访问,值为:{0}" intArray[2 3]);
  12. Console.WriteLine("属性:Length:返回数组中元素的总数,值为:{0}" intArray.Length);

可以使用两个索引访问多维数组的值。第一个索引用于行,第二个索引用于列。两个索引都从零开始。

锯齿状数组

锯齿状数组是数组的数组。Jagged数组直接存储数组而不是任何其他数据类型值。锯齿状数组用两个方括号 [][] 初始化。

第一个括号指定数组的大小,第二个括号指定将作为值存储的数组的维度。(锯齿状数组总是存储一个数组),二维数组的大小是矩形的。

例如:3×3个元素。而锯齿数组的大小设置是比较灵活的,在锯齿数组中,每一行都可以有不同的大小

  1. int[][] intJaggedArray = new int[2][];
  2. intJaggedArray[0] = new int[3]{123};
  3. intJaggedArray[1] = new int[2]{45};
  4. Console.WriteLine(intJaggedArray[0][0]); // 1
  5. Console.WriteLine(intJaggedArray[0][2]); // 3
  6. Console.WriteLine(intJaggedArray[1][1]); // 5

Array

.NET提供了一个抽象类 Array ,作为所有数组的基类。它提供了用于创建,操作,搜索和排序数组的静态方法。**

属性 描述
IsFixedSize 获取一个值,该值指示数组是否带有固定大小
IsReadOnly 获取一个值,该值指示数组是否只读
Length 获取一个 32 位整数,该值表示所有维度的数组中的元素总数
LongLength 获取一个 64 位整数,该值表示所有维度的数组中的元素总数
Rank 获取数组的秩(维度)
方法 描述
Clear 根据元素的类型,设置数组中某个范围的元素为零、为 false 或者为 null
Copy(Array,Array,Int32) 从数组的第一个元素开始复制某个范围的元素到另一个数组的第一个元素位置。长度由一个 32 位整数指定
CopyTo(Array,Int32) 从当前的一维数组中复制所有的元素到一个指定的一维数组的指定索引位置。索引由一个 32 位整数指定
GetLength 获取一个 32 位整数,该值表示指定维度的数组中的元素总数
GetLongLength 获取一个 64 位整数,该值表示指定维度的数组中的元素总数
GetLowerBound 获取数组中指定维度的下界
GetType 获取当前实例的类型。从对象(Object)继承
GetUpperBound 获取数组中指定维度的上界
GetValue(Int32) 获取一维数组中指定位置的值。索引由一个 32 位整数指定
IndexOf(Array,Object) 搜索指定的对象,返回整个一维数组中第一次出现的索引
Reverse(Array) 逆转整个一维数组中元素的顺序
SetValue(Object, Int32) 给一维数组中指定位置的元素设置值。索引由一个 32 位整数指定
Sort(Array) 使用数组的每个元素的 IComparable 实现来排序整个一维数组中的元素
ToString 返回一个表示当前对象的字符串。从对象(Object)继承
  1. Array arr = Array.CreateInstance(Type.GetType("System.Int32"), 3);
  2. arr.SetValue(1 0);
  3. arr.SetValue(3 1);
  4. Console.WriteLine("IsFixedSize:取一个值,该值指示数组是否带有固定大小,值为:{0}" arr.IsFixedSize);
  5. Console.WriteLine("IsReadOnly:取一个值,该值指示数组是否只读,值为:{0}" arr.IsReadOnly);
  6. Console.WriteLine("Length:获取一个 32 位整数,该值表示所有维度的数组中的元素总数,值为:{0}" arr.Length);
  7. Console.WriteLine("LongLength:获取一个 64 位整数,该值表示所有维度的数组中的元素总数,值为:{0}" arr.LongLength);
  8. Console.WriteLine("Rank:获取数组的秩(维度),值为:{0}" arr.Rank);
  9. foreach (var item in arr)
  10. {
  11. Console.WriteLine(item);
  12. }

集合

C#包括在特定系列中包含许多值或对象的专用类,称为集合。C#中有两种类型的集合:非泛型集合泛型集合。每个集合类都实现 IEnumerable 接口,因此可以使用 foreach 循环访问集合中的值。

非泛型集合

System.Collections中命名空间包括以下非泛型集合:

类型 用法
ArrayList ArrayList存储任何类型的对象,如数组。但是,当数组自动增长时,无需像数组那样指定ArrayList的大小
SortedList SortedList存储键和值对。它默认按键的升序自动排列元素。C#包括泛型和非泛型SortedList集合
Stack Stack以LIFO样式存储值(后进先出)。它提供了一个Push()方法来添加一个值,Pop()和Peek()方法来检索值。C#包括通用和非通用堆栈
Queue 队列以FIFO样式(先进先出)存储值。它保持添加值的顺序。它提供了一个Enqueue()方法来添加值,还提供了一个Dequeue()方法来从集合中检索值。C#包括通用和非通用队列
Hashtable Hashtable存储键和值对。它通过比较键的哈希值来检索值
BitArray BitArray管理一个紧凑的位值数组,表示为布尔值,其中true表示该位为on(1),false表示该位为off(0)

ArrayList

可以包含任何数据类型的元素。类似于数组,但是在添加元素时不需要指定ArrayList的大小会自动增长。

要点:

  • 可以存储任何数据类型的项(元素)
  • 添加元素时会自动调整大小
  • 可以包含多个null
  • 可以使用 foreachfor 循环或索引器访问

**

属性 描述
Capacity 获取或设置ArrayList可以包含的元素数
Count 获取ArrayList中实际包含的元素数
IsFixedSize 获取一个值,该值指示ArrayList是否具有固定大小
IsReadOnly 获取一个值,该值指示ArrayList是否为只读
Item 获取或设置指定索引处的元素
方法 描述
Add()/AddRange() Add()方法在ArrayList的末尾添加单个元素。 AddRange()方法将指定集合中的所有元素添加到ArrayList中
Insert()/InsertRange() Insert()方法在ArrayList中的指定索引处插入单个元素。 InsertRange()方法从ArrayList中的指定索引开始插入指定collection的所有元素
Remove()/RemoveRange() Remove()方法从ArrayList中删除指定的元素。 RemoveRange()方法从ArrayList中删除一系列元素
RemoveAt() 从ArrayList中删除指定索引处的元素
Sort() 对ArrayList的整个元素进行排序
Reverse() 反转整个ArrayList中元素的顺序
Contains 检查ArrayList中是否存在指定的元素。如果存在则返回true,否则返回false
Clear 删除ArrayList中的所有元素
CopyTo 将所有元素或元素范围复制到compitible Array
GetRange 从ArrayList返回指定索引中指定数量的元素
IndexOf 搜索指定的元素并返回零基索引(如果找到)。如果找不到元素,则返回-1
ToArray 从ArrayList返回compitible数组
  1. ArrayList arrayList = new ArrayList();
  2. arrayList.Add("wang");
  3. arrayList.Add(1);
  4. // ArrayList允许插入null
  5. arrayList.Add(null);
  6. foreach (var item in arrayList)
  7. {
  8. Console.WriteLine(item);
  9. }

SortedList

SortedList集合默认按键的升序存储键值对SortedList类实现IDictionaryICollection接口,因此可以通过键和索引访问元素。

C#包括两种类型的SortedList,泛型SortedList和非泛型SortedList

要点:

  • C#具有泛型和非泛型 SortedList
  • SortedList 按键的升序存储键值对。键必须是唯一的,不能为null,而值可以为null或重复项
  • 非泛型 SortedList 存储任何数据类型的键和值。因此,需要将值转换为适当的数据类型
  • 键值对可以强制转换为DictionaryEntry
  • 使用索引器访问单个值。SortedList 索引器接受键并返回与之关联的值

**

属性 描述
Capacity 获取或设置SortedList实例可以存储的元素数
Count 获取SortedList中实际包含的元素数
IsFixedSize 获取SortedList中实际包含的元素数
IsReadOnly 获取一个值,该值指示SortedList是否为只读
Item 获取或设置SortedList中指定键的元素
Keys 获取SortedList的键列表
Values 获取SortedList中的值列表
方法 描述
Add(object key, object value) 将键值对添加到SortedList中
Remove(object key) 删除具有指定键的元素
RemoveAt(int index) 删除指定索引处的元素
Contains(object key) 检查SortedList中是否存在指定的键
Clear() 从SortedList中删除所有元素
GetByIndex(int index) 返回存储在内部数组中的索引值
GetKey(int index) 检返回存储在内部数组中指定索引处的键
IndexOfKey(object key) 返回存储在内部数组中的指定键的索引
IndexOfValue(object value) 返回存储在内部数组中的指定值的索引
  1. SortedList sortedList = new SortedList();
  2. sortedList.Add(2 "wang");
  3. sortedList.Add(5 "li");
  4. sortedList.Add(3 5);
  5. //SortedList键可以是任何数据类型,但不能在同一SortedList中添加不同数据类型的键。
  6. sortedList.Add("wang" 32);
  7. for (int i = 0; i < sortedList.Count; i++)
  8. {
  9. Console.WriteLine("key:{0},value:{1}" sortedList.GetKey(i), sortedList.GetByIndex(i));
  10. }
  11. foreach (DictionaryEntry item in sortedList)
  12. {
  13. Console.WriteLine("key:{0},value:{1}" item.Key item.Value);
  14. }

Stack

C#包含一种特殊类型的集合,它以 LIFO 样式存储元素(后进先出)

C#包括通用和非通用堆栈,非泛型堆栈。Stack允许空值以及重复值。它提供了一个 Push() 方法来添加一个值, Pop()Peek() 方法来检索值。

要点:

  • Stack将值存储在LIFO(后进先出)样式中。最后添加的元素将是首先出现的元素
  • 使用Push()方法将元素添加到Stack
  • Pop()方法返回并从堆栈顶部删除元素。在空Stack上调用Pop()方法将引发异常
  • Peek()方法总是返回Stack中最顶层的元素

【C#基础】常用数据结构 - 图2
**

属性 方法
Count 返回Stack中元素的总数
方法 描述
Push 在堆栈顶部插入一个项目
Peek 返回堆栈中的顶部项
Pop 从堆栈顶部删除并返回项目
Contains 检查堆栈中是否存在项目
Clear 从堆栈中删除所有项目
  1. Stack stack = new Stack();
  2. stack.Push("1");
  3. stack.Push(1);
  4. stack.Push(false);
  5. foreach (var item in stack)
  6. {
  7. Console.WriteLine(item);
  8. }

Queue

C#包含System.Collection命名空间中的Queue集合类。队列以FIFO样式(先进先出)存储元素。

Stack集合完全相反。它按照添加顺序包含元素。队列集合允许多个空值和重复值。使用Enqueue()方法添加值,使用Dequeue()方法从队列中检索值。

要点:

  • 队列将值存储在FIFO(先进先出)样式中。首先添加的元素将首先出现
  • 使用Enqueue()方法将元素添加到Queue中
  • Dequeue()方法返回并从队列的开头删除元素。在空队列上调用Dequeue()方法将引发异常
  • Peek()方法总是返回最顶层的元素

【C#基础】常用数据结构 - 图3

属性 描述
Count 返回Stack中元素的总数
方法 描述
Enqueue 将项添加到队列中
Dequeue 从队列的开头删除并返回一个项目
Peek 返回队列中的第一个项目
Contains 检查项目是否在队列中
Clear 从队列中删除所有项目
TrimToSize 将队列的容量设置为队列中的实际项目数
  1. Queue queue = new Queue();
  2. queue.Enqueue("1");
  3. queue.Enqueue(1);
  4. queue.Enqueue(false);
  5. foreach (var item in queue)
  6. {
  7. Console.WriteLine(item);
  8. }

Hashtable

C#包含System.Collections命名空间中的Hashtable集合,类似于通用字典集合。Hashtable集合存储键值对。通过计算每个密钥的哈希码来优化查找,并在内部将其存储在不同的存储桶中,然后在访问值时匹配指定密钥的哈希码。

要点:

  • 存储Key必须唯一的任何数据类型的键值对
  • 键不能为null,而值可以为null
  • 通过比较键的哈希码来检索项目。因此它的性能比Dictionary集合慢
  • 使用默认的哈希码提供程序,即object.GetHash()。还可以使用自定义哈希码提供程序
  • DictionaryEntryforeach语句一起使用以迭代Hashtable

**

属性 描述
Count 获取Hashtable中键/值对的总数
IsReadOnly 获取布尔值,指示Hashtable是否为只读
Item 获取或设置与指定键关联的值
Keys 获取Hashtable中的键的ICollection
Values 获取Hashtable中值的ICollection
方法 描述
Add 将具有键和值的项添加到哈希表中
Remove 从散列表中删除具有指定键的项
Clear 从哈希表中删除所有项目
Contains 检查哈希表是否包含特定密钥
ContainsKey 检查哈希表是否包含特定密钥
ContainsValue 检查哈希表是否包含特定值
GetHash 返回指定键的哈希码
  1. Hashtable hashtable = new Hashtable();
  2. hashtable.Add(1 "wang");
  3. hashtable.Add(3 false);
  4. hashtable.Add(2 "li");
  5. foreach (DictionaryEntry item in hashtable)
  6. {
  7. Console.WriteLine("key:{0}, value:{1}" item.Key item.Value);
  8. }

BitArray

BitArray 类管理一个紧凑型的位值数组,它使用布尔值来表示,其中true表示位是开启的(1),false 表示位是关闭的(0)。当需要存储位,但是事先不知道位数时,则使用点阵列。可以使用整型索引从点阵列集合中访问各项,索引从零开始。

属性 描述
Count 获取 BitArray 中包含的元素个数。
IsReadOnly 获取一个值,表示 BitArray 是否只读。
Item 获取或设置 BitArray 中指定位置的位的值。
Length 获取或设置 BitArray 中的元素个数。
方法 描述
public BitArray And( BitArray value ); 对当前的 BitArray 中的元素和指定的 BitArray 中的相对应的元素执行按位与操作。
public bool Get( int index ); 获取 BitArray 中指定位置的位的值。
public BitArray Not(); 把当前的 BitArray 中的位值反转,以便设置为 true 的元素变为 false,设置为 false 的元素变为 true。
public BitArray Or( BitArray value ); 对当前的 BitArray 中的元素和指定的 BitArray 中的相对应的元素执行按位或操作。
public void Set( int index, bool value ); 把 BitArray 中指定位置的位设置为指定的值。
public void SetAll( bool value ); 把 BitArray 中的所有位设置为指定的值。
public BitArray Xor( BitArray value ); 对当前的 BitArray 中的元素和指定的 BitArray 中的相对应的元素执行按位异或操作。

泛型集合

同传统的集合相比,泛型集合是一种强类型的集合,它解决了类型安全问题,同时避免了集合中每次的装箱与拆箱的操作,提升了性能。

List

List<T>在C#应用程序中是一种快捷、易于使用的泛型集合类型,使用泛型编程为编写面向对象程序增加了极大的效率和灵活性,不会强行对值类型进行装箱和拆箱,或对引用类型进行向下强制类型转换。

名称 描述
Add 将对象添加到 List的结尾处
AddRange 将指定集合的元素添加到 List的末尾
AsReadOnly 返回当前集合的只读 IList包装
BinarySearch(T) 使用默认的比较器在整个已排序的 List中搜索元素,并返回该元素从零开始的索引
BinarySearch(T, IComparer) 使用指定的比较器在整个已排序的 List中搜索元素,并返回该元素从零开始的索引
BinarySearch(Int32, Int32, T, IComparer) 使用指定的比较器在已排序 List的某个元素范围中搜索元素,并返回该元素从零开始的索引
Clear 从 List中移除所有元素
Contains 确定某元素是否在 List中
ConvertAll 将当前 List<T中的元素转换为另一种类型,并返回包含转换后的元素的列表
CopyTo(T[]) 将整个 List<T复制到兼容的一维数组中,从目标数组的开头开始放置
Exists 确定 List<T是否包含与指定谓词所定义的条件相匹配的元素
Find 搜索与指定谓词所定义的条件相匹配的元素,并返回整个 List中的第一个匹配 元素
FindIndex(Predicate) 搜索与指定谓词所定义的条件相匹配的元素,并返回整个List 中第一个匹配元素的从零开始的索引
ForEach 对 List的每个元素执行指定操作。 GetEnumerator 返回循环访问 List的枚举器
IndexOf(T) 搜索指定的对象,并返回整个 List中第一个匹配项的从零开始的索引
Insert 将元素插入 List的指定索引处
InsertRange 将集合中的某个元素插入 List的指定索引处
LastIndexOf(T) 搜索指定的对象,并返回整个 List中最后一个匹配项的从零开始的索引
Remove 从 List中移除特定对象的第一个匹配项
Reverse() 将整个 List中元素的顺序反转
Sort() 使用默认比较器对整个 List中的元素进行排序
  1. List<intintList = new List<int>();
  2. intList.Add(3);
  3. intList.Add(54);
  4. intList.Add(14);
  5. foreach (var item in intList)
  6. {
  7. Console.WriteLine(item);
  8. }

Stack

后进先出的方式维护数据的集合,包含pop()push(),从栈内压入或移除数据。

Quenue

先进先出的方式访问数据,使用Enqueue()Dequeue()添加数据和移除数据。

SortedSet

这个类中的数据是排序的,在插入和移除数据之后仍然能自动排序,需要向其构造函数中传递一个实现了IComparer<T>,该接口定义了Compare方法。

ObservableCollection

表示能在添加、移除或者刷新整个列表时提供通知的动态数据集合, ReadOnlyObservableCollection<T> 的操作与之类似,不过是只读的。 ObservableCollection<T> 实现了一个名为CollectionChanged事件,该事件在插入新的数据或者移除数据时触发。

Dictionary

提供快速的基于键值的元素查找。结构是:Dictionary <[key],[value]>,当有很多元素的时候可以用它。在使用前,必须声明它的键类型和值类型。

数组/ArrayList/List三者的区别

  • 数组:针对特定类型固定长度,值不可为null,在声明数组的时候必须指定数组的长度,可有多个维度
  • Array:数组的另一种创建方式抽象类,作为所有数组的基类,针对任意类型固定长度,值可以为null,输出会被替换为0
  • ArrayList:针对任意类型、任意长度的,值可以为null,存储或检索值类型时通常发生装箱和拆箱操作,带来很大的性能耗损
  • List:强类型的集合,固定类型、任意长度,值不可为null,是类型安全的

    索引器(Indexer)

    Indexer是一种特殊类型的属性,允许以与其内部集合的数组相同的方式访问类或结构。除了使用带有方括号和参数的此关键字定义的属性外,它与属性相同。

  • 索引器与属性相同,除了它使用带有方括号的此关键字定义,该参数具有参数

  • 可以通过具有不同类型的参数来覆盖索引器
  • 不支持使用索引器的Refout参数
  • 索引器可以作为接口成员包含在内
  1. public <return typethis[<parameter typeindex]
  2. {
  3. Get{
  4. // return the value from the specified index
  5. }
  6. Set{
  7. // set values at the specified index
  8. }
  9. }
  1. public class Indexer
  2. {
  3. private int[] indexs = new int[10];
  4. public int this[int index]
  5. {
  6. get { return indexs[index]; }
  7. set
  8. {
  9. indexs[index] = value;
  10. }
  11. }
  12. }
  13. /*
  14. Indexer是一种特殊类型的属性,允许以与其内部集合的数组相同的方式访问类或结构。
  15. 除了使用带有方括号和参数的此关键字定义的属性外,它与属性相同。
  16. */
  17. Console.WriteLine("********************索引器*********************");
  18. Indexer indexer = new Indexer();
  19. indexer[0] = 1;
  20. indexer[1] = 2;
  21. Console.WriteLine(indexer[1]);