参考:
https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/collections
https://www.runoob.com/csharp/csharp-tutorial.html
注:在方法和属性部分列举了一些常用,并部分在示例代码中有使用
1、数组(Array)
1.1 数组的基本特、和声明及初始化
1.数组的特点
数组是一种数据结构,它包含若干相同类型的变量,内存连续储存,节约空间,可以索引访问,读取快,增删慢。但是数组不能增加元素,长度固定。
数组具有以下的特点:
- 数组属于线性结构,在内存中是连续存放的。
- 数组的元素类型必须相同。
- 数组可以直接通过下标访问。
- 数组的查找速度非常快,新增和删除速度慢。
- 数组在初始化时要指定数组长度。
2.数组声明及初始化
type[] arrayName = new type[]{数组元素初始化列表} ;
type[] arrayName = new type[数组长度] ;
例如:
//定义一个长度为5的int一维数组,并赋予值{1,2,3,4,5}。如果不赋值,int 数组的所有元素都会被初始化为 0。
int[] intArr1 = new int[5]{1,2,3,4,5};
//指定类型同时给元素赋值,具体大小由编译器自动推断
string[] strArr1 = new string[]{"1","2","3","4","5"};
//定义一个2×3的二维数组并赋值,类似于一个二维矩阵
int[,] intArr2 = new int[2,3]{{1,2,3},{4,5,6}};
//C#交错数组:是一个一维数组
int[][] scores1 = new int[2][]{new int[]{92,93,94},new int[]{85,66,87,88}};//由2各int数组组成的数组
1.2数组的访问及常用属性和方法
1.数组的访问
数组中的元素是通过使用下标(二维数组使用行索引和列索引)来访问。
int i = intArr1[1]; //i=2
int j = intArr2[1,2]; //j=6
//C#交错数组的访问
int k = scores1[1][2]; //k=87
2.数组对应位置值的修改
//索引位置直接赋予对应位置的值
intArr1[1]=3; //intArr1={1,3,3,4,5}
//二维数组的intArr2中的第i行,第j列元素赋值给交错数组中第i个数组的第j个位置
scores1[i][j]=intArr2[i,j];
3.常用方法和属性
参考:https://www.runoob.com/csharp/csharp-array-class.html
常用方法、属性(方法中的变量这里省略) | 说明 |
---|---|
Length | 获得一个32位整数,该整数表示Array的所有维数中元素的总数,即数组的元素个数,常用来限制数组下标的大小。 |
Rank | 获取数组的秩(维度)。 |
CopyTo() | 使用数组对象的CopyTo()方法进行复制,array表示复制的数组,index表示开始位置。 |
Copy() | 数组的第一个元素开始复制某个范围的元素到另一个数组的第一个元素位置。 |
GetValue() | 返回对应索引下的元素 |
IndexOf() | 搜索指定的对象,返回整个一维数组中第一次出现的索引。 |
LastIndexOf() | 查找数组中是否含有某个元素,返回该元素最后一次出现的位置 |
ToString() | 返回一个表示当前对象的字符串。从对象(Object)继承。 |
Sort() | 使用数组的每个元素的 IComparable 实现来排序整个一维数组中的元素。 |
Clear() | 清空数组中的元素 |
使用foreach()循环遍历数组 | 遍历数组的每个元素并进行对应操作 |
代码示例:
static void Main(string[] args)
{
int[] intArr1 = new int[] { 1, 2, 3, 4, 5, 6, 7,8,2,3 };
Console.Write("循环遍历数组: ");
foreach (int i in intArr1)
{
Console.Write(i + " ");
}
Console.WriteLine();
// 逆转数组
Array.Reverse(intArr1);
Console.Write("逆转数组: ");
foreach (int i in intArr1)
{
Console.Write(i + " ");
}
Console.WriteLine();
// 排序数组
Array.Sort(intArr1);
Console.Write("排序数组: ");
foreach (int i in intArr1)
{
Console.Write(i + " ");
}
Console.WriteLine();
//获取数组的长度
int Long1 = intArr1.Length;
Console.Write(Long1 + "\n");
//获取数组第一个2和最后一个2的索引
int Index1 = Array.IndexOf(intArr1,2);
Console.Write(Index1+"\n");
int Index2 = Array.LastIndexOf(intArr1, 2);
Console.Write(Index2 + "\n");
//清除数组
Array.Clear(intArr1, 2, 3); //数组长度不变,清除位置以零代替
Console.Write("循环遍历清除后的数组: ");
foreach (int i in intArr1)
{
Console.Write(i + " ");
}
Console.WriteLine();
Console.ReadKey();
}
结果:
循环遍历数组: 1 2 3 4 5 6 7 8 2 3
逆转数组: 3 2 8 7 6 5 4 3 2 1
排序数组: 1 2 2 3 3 4 5 6 7 8
10
1
2
循环遍历清除后的数组: 1 2 0 0 0 4 5 6 7 8
2. 集合
集合(Collection)和数组比较类似,可以看成一个特殊的数组,都用于存放一组值,但集合中提供特定的方法能直接操作集合中的数据,并提供了不同的集合类来实现特定的功能。C#中常见的集合有:动态数组(ArrayList)、链表(Queue)、堆栈(Stack)、哈希表(Hashtable)等。
2.1 动态数组(ArrayList)
1. ArrayList特点
ArrayList的底层实际是一个 表示对象的数组,这些对象的大小会根据需要动态增加,读取快,增删慢。
动态数组具有以下的特点:
- ArrayList在声明时不必指定长度。
- ArrayList会把所有的元素都当做Object处理,可以存储不同数据类型的元素。
- 插入和删除一个元素时,会移动它之后所有元素的位置,效率低,频繁进行插入或者删除元素推荐使用双向链表(LinkedList)。
- ArrayList是非类型安全的,在插入和删除元素时会进行拆箱和装箱问题,影响性能,效率低。
所在命名空间为:using System.Collections;
非泛型
2.声明、赋值及访问
ArrayList在使用过程中如果集合长度不足其容量自动增长一倍,而且集合的长度会双倍增长。
声明:
ArrayList list1 = new ArrayList(可指定最大容量);
//示例:
ArrayList arrlist = new ArrayList(2); //声明一个ArrayList,并指定当前最大容量为2
arrlist.Add(4);
arrlist.Add("5");
int Cap0 = arrlist.Capacity;
Console.WriteLine(Cap0);//打印此时的容量
arrlist.Add(6);
int Cap1 = arrlist.Capacity;
Console.WriteLine(Cap1); //打印此时的容量
//读取第2个位置的元素并打印
Console.WriteLine(arrlist[1]);
//结果
2
4
5
3.常见属性和方法
常用方法、属性(方法中的变量这里省略) | 说明 |
---|---|
Count | 代表着Arraylist集合实际包含元素的个数,也就是说集合里面有二个元素那么Count属性的值就为2 |
Capacity | 代表Arraylist集合最大可包含的元素个数 |
Add() | 增加元素到集合末尾处 |
AddRange() | 在末尾添加一个ICollection的元素 |
Insert() | 在指定位置处插入元素 |
Remove() | 删除元素 |
RemoveAt() | 删除指定位置元素 |
Sort() | 排序 |
Reverse() | 反转 |
clear() | 清空集合 |
Contains() | 判断某元素是否在集合中 |
IndexOf() | 返回某个值在集合中的第一个索引 |
代码示例:
static void Main(string[] args)
{
ArrayList arrlist = new ArrayList(3);
ArrayList arrlist1 = new ArrayList() {4,5,9 };
Console.WriteLine("添加元素");
arrlist.Add(45);
Console.WriteLine("添加ArrayList");
arrlist.AddRange(arrlist1);
Console.WriteLine("Capacity: {0} ", arrlist.Capacity);
Console.WriteLine("Count: {0}", arrlist.Count);
Console.Write("遍历元素: ");
foreach (int i in arrlist)
{
Console.Write(i + " ");
}
Console.WriteLine();
Console.Write("排序: ");
arrlist.Sort();
foreach (int i in arrlist)
{
Console.Write(i + " ");
}
arrlist[3] = 29; //修改3索引位置的元素
arrlist.RemoveAt(2);//删除在索引位置的元素
arrlist.Insert(2,10);//在2索引位置后加一个元素10
Console.Write("\n"+"结果: ");
foreach (int i in arrlist)
{
Console.Write(i + " ");
}
arrlist.Clear(); //清空数组
Console.ReadKey();
}
//结果
Capacity: 6
Count: 4
遍历元素: 45 4 5 9
排序: 4 5 9 45
结果: 4 5 10 29
2.2 队列(Queue)
1.队列的特点
队列(Queue)是一个先进先出的对象集合。
- 队列(Queue)是先进先出的原则,最先进入的元素最先被访问,最后进入的元素最后被访问。
- Enqueue入队列,Dequeue出队列并返回列首元素,Peek只返回列首元素。
**声明:**Queue q = new Queue();
所在命名空间为:using System.Collections;
有对应的泛型:Queue< T > q2 = new Queue< T>();
2. 队列(Queue)基本属性和方法
常用方法、属性(方法中的变量这里省略) | 说明 |
---|---|
Count | 包含的元素个数 |
Clear() | 移除队列中的所有元素 |
Contains() | 判断某个元素是否在Queue中 |
Dequeue() | 移除并返回Queue的开头的对象 |
Enqueue() | 向Queue的末尾添加一个对象 |
ToArray() | 复制Queue到一个新的数组中 |
TrimToSize() | 设置容量为Queue中元素的实际个数 |
代码示例:
static void Main(string[] args)
{
Queue q = new Queue();
//向队尾追加元素
q.Enqueue('A');
q.Enqueue('M');
q.Enqueue('G');
q.Enqueue('W');
Console.WriteLine("当前的队列内容: ");
foreach (char c in q)
Console.Write(c + " ");
Console.WriteLine();
//继续追加
q.Enqueue('V');
q.Enqueue('H');
Console.WriteLine("当前的队列内容: ");
foreach (char c in q)
Console.Write(c + " ");
Console.WriteLine();
Console.WriteLine("移除一些值: ");
char ch = (char)q.Dequeue();//使用字符char来接收,这里需要转数据类型
Console.WriteLine("移除的值: {0}", ch);
ch = (char)q.Dequeue();
Console.WriteLine("移除的值: {0}", ch);
Object[] q1= (Object[])q.ToArray();
Console.WriteLine(q1.GetType());
Console.WriteLine("数组的内容: ");
foreach (char c in q1)
Console.Write(c + " ");
char chr = (char)q.Peek(); //返回列首元素
Console.WriteLine("\n当前列首元素: "+chr+"\n");
q.Clear();
Console.ReadKey();
}
//结果
当前的队列内容:
A M G W
当前的队列内容:
A M G W V H
移除一些值:
移除的值: A
移除的值: M
System.Object[]
数组的内容:
G W V H
当前列首元素: G
2.3 堆栈(Stack)
1.堆栈的特点
堆栈(Stack)是一个后进先出的对象集合,而不能在中间插入或删除元素。当您需要对各项进行后进先出的访问时,则使用堆栈。
- 堆栈是先进后出的原则,最先插入的元素最后被访问,最后插入的元素最先被访问。
- Push入栈,Pop出栈并返回栈顶元素,Peek只返回栈顶元素。
声明: Stack st = new Stack();
所在命名空间为:using System.Collections;
有对应的泛型:Stack< T> st = new Stack< T>();
2.队列(Queue)基本属性和方法
常用方法、属性(方法中的变量这里省略) | 说明 |
---|---|
Count | 包含的元素个数 |
Pop() | 移除并返回在 Stack 的顶部的对象。 |
Push( ) | 向 Stack 的顶部添加一个对象。 |
Peek() | 返回在 Stack 的顶部的对象,但不移除它。 |
代码示例:
static void Main(string[] args)
{
Stack st = new Stack();
//向堆栈中放入元素
st.Push('A');
st.Push('M');
st.Push('G');
st.Push('W');
Console.WriteLine("当前的堆栈: ");
foreach (char c in st)
{
Console.Write(c + " ");
}
Console.WriteLine();
st.Push('V');
st.Push('H');
Console.WriteLine("堆栈的顶部对象: {0}",
st.Peek());
Console.WriteLine("当前的堆栈: ");
foreach (char c in st)
{
Console.Write(c + " ");
}
Console.WriteLine();
Console.WriteLine("移除值 ");
char chr1 = (char)st.Pop();
st.Pop();
char chr2 = (char)st.Pop();
Console.WriteLine("被移除的对象1: "+ chr1);
Console.WriteLine("被移除的对象2: "+ chr2);
Console.WriteLine("当前的堆栈:");
foreach (char c in st)
{
Console.Write(c + " ");
}
}
//结果
当前的堆栈:
W G M A
堆栈的顶部对象: H
当前的堆栈:
H V W G M A
移除值
被移除的对象1: H
被移除的对象2: W
当前的堆栈:
G M A
2.4 哈希表(Hashtable)
1.哈希表特点
**哈希表(Hashtable)**用于处理和表现类似key/value的键值对,其中key通常可用来快速查找,同时key是区分大小写;value用于存储对应于key的值。Hashtable中key/value键值对均为object类型,所以Hashtable可以支持任何类型的key/value键值对。Hashtable是无序的,读取时,它并不按照你加入的先后顺序读出来。
**HashTable的使用:**多线程程序中推荐使用 Hashtable, 默认的 Hashtable 允许单线程写入, 多线程读取, 对 Hashtable 进一步调用 Synchronized()方法可以获得完全线程安全的类型,如:
Hashtable hashtable = System.Collections.Hashtable.Synchronized(new Hashtable());
。而Dictionary 非线程安全, 必须人为使用 lock 语句进行保护, 效率大减,但是无需装箱拆箱,即把对象转为object,或者把object转为对象。因此,在以下情况使用哈希表:1)某些数据会被高频率查询(2)数据量大(3)查询字段包含字符串类型(4)数据类型不唯一
声明:Hashtable hashtable = new Hashtable();
查询:typeofvalue name = hasht[k]; //k为值所对应的键,返回值
不支持泛型
2.哈希表的常用属性和方法
常用方法、属性(方法中的变量这里省略) | 说明 |
---|---|
IsFixedSize | 获取一个值,该值指示Hashtable是否具有固定大小 |
IsReadOnly | 获取一个值,该值指示Hashtable知否为只读 |
IsSynchronized | 获取一个值,该值指示是否同步对Hashtable的访问 |
Item | 设置或获取与指定的键相关联的值 |
Keys | 获取包含Hashtable中的键的ICollection |
Values | 获取包含Hashtable中的值的ICollection |
Add() | 向Hashtable中添加元素 |
Clear() | 从Hashtable中移除所有元素 |
Remove() | 从Hashtable中移除带有指定键的元素 |
Contains() | 用来确定Hashtable中是否包含特定键 |
ContainsValue() | 确定Hashtable中是否包含特定值 |
代码示例:
static void Main(string[] args)
{
Hashtable ht = new Hashtable();
//向Hashtable中添加键值对
ht.Add("001", "张三");
ht.Add("002", "李四");
ht.Add("003", "王五");
ht.Add("004", "李华");
ht.Add("005", "刘希");
//判断张三是否在哈希表中
if (ht.ContainsValue("张三"))
{
Console.WriteLine("在里面");
}
else
{
ht.Add("006", "张三"); //没有的话就添加
}
// 获取键的集合
ICollection key = ht.Keys;
// 获取值的集合
ICollection values = ht.Values;
//遍历键的集合
foreach (string k in key)
{
Console.WriteLine(k + ": " + ht[k]);
}
Console.ReadKey();
}
//结果
在里面
005: 刘希
003: 王五
001: 张三
004: 李华
002: 李四
3. 泛型集合List< T >
3.1 List< T >的特点
List< T >是ArrayList的泛型类,内存上都是连续摆放,不定长度,泛型,保证类型安全,避免装箱拆箱 性能也比ArrayList高, 读取快,增删慢。
泛型List具有以下的特点:
- 泛型List需要在声明时指定具体的类型,如list< int >中添加string等非int类型的成员添加不进去(编译都过不去),这样数据就安全唯一了。
- 节省性能,泛型List没有装箱和拆箱操作,即把对象转为object,或者把object转为对象,因此List比ArrayList效率高而且类型安全。
3.2泛型集合List< T >的属性和方法
常用方法、属性(方法中的变量这里省略) | 说明 |
---|---|
Add() | 将东西加入到列表的最后 |
Remove() | 删掉项中第一个匹配你想删除的条件的项(删去第一个匹配此条件的项)。 |
Clear() | 清空所有项。 |
Sort() | 用系统默认的方式对项进行排序。 |
Contains() | 查看某项是否存在于列表中。 |
LastIndexOf() | 返回最后一个元素 |
FindLastIndex() | 返回最后一个元素的索引 |
CopyTo( ) | 把一个List拷贝到一维数组内 |
Exists( ) | 测试一个元素是否在List内 |
Find( ) | 查找并返回List内的出现的第一个匹配元素 |
IndexOf( ) | 查找并返回每一个匹配元素的索引 |
static void Main(string[] args)
{
List<int> a = new List<int>() { 1,4,3,2,7};
//添加元素
a.Add(2);
a.Add(10);
Console.WriteLine($"第一个数为{a[0]}");
a.Remove(2);//删去第一个匹配此条件的项
a.Sort();
foreach (var a2 in a)
{
Console.Write(a2+" ");
}
bool a3 = a.Contains(2);
Console.WriteLine("\n"+a3);
//定义一个条件
var predicate = new Predicate<int>(num => num % 2 == 0);
//判断是否有包含该条件的元素
bool a4 = a.Exists(predicate);
Console.WriteLine(a4);
Console.ReadKey();
}
//结果
第一个数为1
1 2 3 4 7 10
True
True
4.字典(Dictionary<K,T>)
4.1字典的特点
Dictionary<TKey,TValue> 是 C# 中使用非常频繁的一种数据结构,其中每个元素都是由键值对(Key/Value)组成,以Hashtable一样。Dictionary是有序的,读取时,它按照你加入的先后顺序读出来。
字典具有以下特点:
- 创建字典时需要指定key和value的数据类型。
- 字典中的key值是唯一的,不能为空,value的值可以不唯一。
- 可以通过key快速查找对应的value,速度快,但是消耗内存。
初始化:Dictionary<TKey,TValue> testDict = new Dictionary<TKey,TValue>();
4.2常用属性及方法
常用方法、属性(方法中的变量这里省略) | 说明 |
---|---|
Comparer | 确定字典中的键是否相等的IEqualityComparer |
Count | 获取包含在 Dictionary<TKey, TValue> 中的键/值对的数目 |
Keys | 获取包含 Dictionary<TKey, TValue> 中的键的集合 |
Values | 获取包含Dictionary<TKey, TValue> 中的值的集合 |
Equals() | 确定指定的 Object 是否等于当前的 Object |
GetType () | 获取当前实例的 Type |
ContainsValue() | 确定 Dictionary是否包含特定值。 |
ContainsKey() | 确定 Dictionary是否包含指定的键。 |
代码示例:
static void Main(string[] args)
{
Dictionary<int, String> a = new Dictionary<int, String>() {
{03,"王五"},
{04,"华子" }
}; //初始化一个字典
a.Add(01, "张三");
a.Add(02, "李四");
Console.WriteLine("删去前的Count" + a.Count);
a.Remove(01);
//遍历字典
foreach (KeyValuePair<int, string> kvp in a)
{
Console.WriteLine($"{kvp.Key}"+":"+ $"{kvp.Value}");
}
Console.WriteLine(a[04]);
Console.WriteLine(a.Count);
Console.WriteLine(a.ContainsKey(01));
Console.ReadKey();
}
//结果
删去前的数:4
3:王五
4:华子
2:李四
华子
3
False
5 双向链表(LinkedList< T>)
5.1 双向链表的特点
链表它是一种链状的结构,每个结点都是离散的,增删快,读取慢。
- 无法通过下标查找元素,在查找链表元素时,总是从头结点开始查找,不自带排序方法。
- 容量是链表最大包含的元素数,会根据元素增减而动态调整容量。值可以为 null,并允许重复值。
初始化:LinkedList< T> list 1= new LinkedList< T>();
5.2 双向链表的常用方法
常用方法、属性(方法中的变量这里省略) | 说明 |
---|---|
Count | 获取实际节点数 |
First | 获取第一个节点 |
Last | 获取最后一个节点 |
AddAfter() | 在指定现有节点后添加包含指定值的新节点 |
AddBefore() | 在指定现有节点前添加包含指定值的新节点 |
AddFirst() | 在开头处添加包含指定值的新节点 |
AddLast() | 在结尾处添加包含指定值的新节点 |
Find () | 查找包含指定值的第一个节点 |
Contains() | 确定某值是否在 |
Remove() | 移除指定值的第一个匹配项 |
CopyTo (T[] array, int index); | 将整个 LinkedList 复制到指定一维数组的指定索引处 |
代码示例:
static void Main()
{
LinkedList<string> Link1 = new LinkedList<string>();
Link1.AddLast("01");
Link1.AddLast("02");
LinkedListNode<string> node1 = Link1.Find("01");
Link1.AddBefore(node1, "03");
Link1.AddFirst("04");
foreach (var ele in Link1)
{
Console.Write (ele +" ");
}
Console.WriteLine("\n复制到Array: \n");
// LinkedList 复制到指定一维数组的指定索引处
String[] ArrS= new String[Link1.Count];
Link1.CopyTo(ArrS, 0);
foreach (var item in ArrS)
{
Console.Write(item+" ");
}
Console.ReadKey();
}
//结果
04 03 01 02
复制到Array:
04 03 01 02
总结:
集合类总体可分为一下几类:关联/非关联型集合,顺序/随机访问集合,顺序/无序集合,泛型/非泛型集合,线程安全集合。
各集合类底层接口关系图
参考: https://blog.csdn.net/chen8238065/article/details/47018271*
以上就是我总结的有关C#常用的数据结构,仅供交流学习!
欢迎关注个人微信公众号【智能建造小硕】(分享计算机编程、人工智能、智能建造、日常学习和科研经验等,欢迎大家关注交流。)