1. CSharp中的集合
集合(Collection)类是专门用于数据存储和检索的类。这些类提供了对栈(stack)、队列(queue)、列表(list)和哈希表(hash table)的支持。大多数集合类实现了相同的接口。
集合(Collection)类服务于不同的目的,如为元素动态分配内存,基于索引访问列表项等等。这些类创建 Object 类的对象的集合。在 C# 中,Object 类是所有数据类型的基类。
1.1. 各种集合类
1.1.1. 动态数组(ArrayList)
-
它代表了可被单独索引的对象的有序集合。
-
它基本上可以替代一个数组。但是,与数组不同的是,您可以使用索引在指定的位置添加和移除项目,动态数组会自动重新调整它的大小。它也允许在列表中进行动态内存分配、增加、搜索、排序各项。
1.1.2. 哈希表(Hashtable)
-
它使用键来访问集合中的元素。
-
当您使用键访问元素时,则使用哈希表,而且您可以识别一个有用的键值。哈希表中的每一项都有一个键/值对。键用于访问集合中的项目。
1.1.3. 排序列表(SortedList)
-
它可以使用键和索引来访问列表中的项。
-
排序列表是数组和哈希表的组合。它包含一个可使用键或索引访问各项的列表。如果您使用索引访问各项,则它是一个动态数组(ArrayList),如果您使用键访问各项,则它是一个哈希表(Hashtable)。集合中的各项总是按键值排序。
1.1.4. 堆栈(Stack)
-
它代表了一个后进先出的对象集合。
-
当您需要对各项进行后进先出的访问时,则使用堆栈。当您在列表中添加一项,称为推入元素,当您从列表中移除一项时,称为弹出元素。
1.1.5. 队列(Queue)
-
它代表了一个先进先出的对象集合。
-
当您需要对各项进行先进先出的访问时,则使用队列。当您在列表中添加一项,称为入队,当您从列表中移除一项时,称为出队。
1.1.6. 点阵列(BitArray)
-
它代表了一个使用值 1 和 0 来表示的二进制数组。
-
当您需要存储位,但是事先不知道位数时,则使用点阵列。您可以使用整型索引从点阵列集合中访问各项,索引从零开始。
1.2. 泛型集合List
集合是OOP中的一个重要概念,C#中对集合的全面支持更是该语言的精华之一。
1.3. 为什么要用泛型集合?
在C# 2.0之前,主要可以通过两种方式实现集合:
- 使用ArrayList
直接将对象放入ArrayList,操作直观,但由于集合中的项是Object类型,因此每次使用都必须进行繁琐的类型转换。
- 使用自定义集合类
比较常见的做法是从CollectionBase抽象类继承一个自定义类,通过对IList对象进行封装实现强类型集合。这种方式要求为每种集合类型写一个相应的自定义类,工作量较大。泛型集合的出现较好的解决了上述问题,只需一行代码便能创建指定类型的集合。
string strPrefix = txtPrefix.Text;
int count = Convert.ToInt32(txtNumCount.Text);
List<string> listData= new List<string>();
for (int i = 0; i < count; i++)
{
listData.Add(strPrefix + i);
}
int count = Convert.ToInt32(txtNumCount.Text);
List<int> listData = new List<int>();
for (int i = 0; i < count; i++)
{
listData.Add(i);
}
List<Person> listData = new List<Person>();
listData.Add(new Person("张三",17));
listData.Add(new Person("李四",18));
listData.Add(new Person("王五",19));
class Person
{
private string _name; //姓名
private int _age; //年龄
//创建Person对象
public Person(string Name, int Age)
{
this._name= Name;
this._age = Age;
}
//姓名
public string Name
{
get { return _name; }
}
//年龄
public int Age
{
get { return _age; }
}
}
2. CSharp中的字典
2.1. Dictionary
- 必须包含名空间System.Collection.Generic
- Dictionary里面的每一个元素都是一个键值对(由二个元素组成:键和值)
- 键必须是唯一的,而值不需要唯一的
- 键和值都可以是任何类型(比如:string, int, 自定义类型,等等)
- 通过一个键读取一个值的时间是接近O(1)
- 键值对之间的偏序可以不定义
string strPrefix = txtPrefix.Text;
int count = Convert.ToInt32(txtNumCount.Text);
Dictionary<string,bool> dicData = new Dictionary<string,bool>();
for (int i = 0; i < count; i++)
{
dicData.Add(strPrefix + i,true);
}
int count = Convert.ToInt32(txtNumCount.Text);
Dictionary<int, bool> dicData = new Dictionary<int, bool();
for (int i = 0; i < count; i++)
{
dicData.Add(i, true);
}
//定义
Dictionary<string, string> openWith = new Dictionary<string,string>();
//添加元素
openWith.Add("txt", "notepad.exe");
openWith.Add("bmp", "paint.exe");
openWith.Add("dib", "paint.exe");
openWith.Add("rtf", "wordpad.exe");
3.CSharp中泛型集合与字典的内存使用情况
我们现在建立两组数据,向List<string> listData
、Dictionary<string,bool> dicData
、List<int> listData
、Dictionary<int, bool> dicData
4个集合中添加数据
private void btnAutomaticMemory_Click(object sender,EventArgs e)
{
string strPrefixInfo = txtPrefix.Text;
Console.WriteLine("********************************************************************");
Console.WriteLine($"字符串为【{strPrefixInfo}】");
Console.WriteLine("********************************************************************");
AlterPrefixAndNumCount(strPrefixInfo, 10);
AutomaticMemory(10);
AlterPrefixAndNumCount(strPrefixInfo, 100);
AutomaticMemory(100);
AlterPrefixAndNumCount(strPrefixInfo, 1000);
AutomaticMemory(1000);
AlterPrefixAndNumCount(strPrefixInfo, 10000);
AutomaticMemory(10000);
AlterPrefixAndNumCount(strPrefixInfo, 20000);
AutomaticMemory(20000);
AlterPrefixAndNumCount(strPrefixInfo, 50000);
AutomaticMemory(50000);
AlterPrefixAndNumCount(strPrefixInfo, 100000);
AutomaticMemory(100000);
AlterPrefixAndNumCount(strPrefixInfo, 200000);
AutomaticMemory(200000);
AlterPrefixAndNumCount(strPrefixInfo, 500000);
AutomaticMemory(500000);
AlterPrefixAndNumCount(strPrefixInfo, 1000000);
AutomaticMemory(1000000);
AlterPrefixAndNumCount(strPrefixInfo, 2000000);
AutomaticMemory(2000000);
AlterPrefixAndNumCount(strPrefixInfo, 5000000);
AutomaticMemory(5000000);
AlterPrefixAndNumCount(strPrefixInfo, 10000000);
AutomaticMemory(10000000);
AlterPrefixAndNumCount(strPrefixInfo, 20000000);
AutomaticMemory(20000000);
}
private void AutomaticMemory(int numCount)
{
Console.Write($"| {numCount} |");
btnLoadListStringData_Click(null, null);
btnLoadDictionaryStringData_Click(null, null);
btnLoadListIntData_Click(null, null);
btnLoadDictionaryIntData_Click(null, null);
Console.WriteLine("");
}
/// <summary>
/// 加载集合数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnLoadListStringData_Click(object sender, EventArgs e)
{
string strPrefix = txtPrefix.Text;
int count = Convert.ToInt32(txtNumCount.Text);
List<string> listData= new List<string>();
for (int i = 0; i < count; i++)
{
listData.Add(strPrefix + i);
}
ShowProcessInfoTabel();
}
private void btnLoadDictionaryStringData_Click(object sender, EventArgs e)
{
string strPrefix = txtPrefix.Text;
int count = Convert.ToInt32(txtNumCount.Text);
Dictionary<string,bool> dicData = new Dictionary<string, bool>();
for (int i = 0; i < count; i++)
{
dicData.Add(strPrefix + i,true);
}
ShowProcessInfoTabel();
}
private void btnLoadListIntData_Click(object sender, EventArgs e)
{
int count = Convert.ToInt32(txtNumCount.Text);
List<int> listData = new List<int>();
for (int i = 0; i < count; i++)
{
listData.Add(i);
}
ShowProcessInfoTabel();
}
private void btnLoadDictionaryIntData_Click(object sender, EventArgs e)
{
int count = Convert.ToInt32(txtNumCount.Text);
Dictionary<int, bool> dicData = new Dictionary<int, bool>();
for (int i = 0; i < count; i++)
{
dicData.Add(i, true);
}
ShowProcessInfoTabel();
}
/// <summary>
/// 显示程序的内存占用信息
/// </summary>
/// <param name="strPhaseInfo"></param>
public void ShowProcessInfoTabel()
{
//实时分析内存至关重要
GC.Collect();
var name = Process.GetCurrentProcess().ProcessName;
PerformanceCounter curpcp = new PerformanceCounter("Process", "Working Set - Private", name);
PerformanceCounter curtime = new PerformanceCounter("Process", "% Processor Time", name);
Console.Write($" {curpcp.NextValue() / MB_DIV} |");
Application.DoEvents();
}
3.1. 连续数字集合内存占用
个数 | 连续数字集合内存占用MB | 连续数字字典内存占用MB |
---|---|---|
10 | 8.90625 | 8.945313 |
100 | 8.945313 | 8.945313 |
1000 | 8.945313 | 8.945313 |
10000 | 10.01563 | 10.42188 |
20000 | 11.86719 | 12.58203 |
50000 | 14.58203 | 16.59766 |
100000 | 15.56641 | 19.82422 |
200000 | 16.83203 | 25.68359 |
500000 | 18.67578 | 24.97266 |
1000000 | 22.80859 | 35.58984 |
2000000 | 22.83594 | 56.76563 |
5000000 | 35.17188 | 115.2852 |
10000000 | 55.85156 | 216.0703 |
3.2. 字符串集合内存占用:君子慎独,不欺暗室。 卑以自牧,含章可贞。
个数 | 集合内存占用MB | 字典内存占用MB |
---|---|---|
10 | 10.47656 | 8.78125 |
100 | 8.945313 | 8.945313 |
1000 | 8.945313 | 8.945313 |
10000 | 9.375 | 10.53516 |
20000 | 10.57031 | 12.83203 |
50000 | 13.36719 | 19.13672 |
100000 | 15.84375 | 27.03125 |
200000 | 29.44922 | 40.51953 |
500000 | 50.52734 | 60.5 |
1000000 | 86.64063 | 105.9297 |
2000000 | 155.6563 | 203.5977 |
5000000 | 391.207 | 474.2734 |
10000000 | 771.125 | 936.5156 |
3.2. 字符串集合内存占用:臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。
个数 | 集合内存占用MB | 字典内存占用MB |
---|---|---|
10 | 10.58594 | 8.902344 |
100 | 9.0625 | 9.0625 |
1000 | 9.0625 | 9.0625 |
10000 | 11.09766 | 14.29688 |
20000 | 14.18359 | 19.70313 |
50000 | 19.75 | 27.85547 |
100000 | 35.87109 | 42.65234 |
200000 | 54.32422 | 71.60547 |
500000 | 127.8242 | 137.7461 |
1000000 | 242.6445 | 262.5938 |
2000000 | 464.4609 | 514.0898 |
5000000 | 1146.625 | 1235.301 |
10000000 | 2291.086 | 2459.48 |
********************************************************************
字符串为【君子慎独,不欺暗室。 卑以自牧,含章可贞。】
********************************************************************
| 10 | 10.47656 | 8.78125 | 8.90625 | 8.945313 |
| 100 | 8.945313 | 8.945313 | 8.945313 | 8.945313 |
| 1000 | 8.945313 | 8.945313 | 8.945313 | 8.945313 |
| 10000 | 9.375 | 10.53516 | 10.01563 | 10.42188 |
| 20000 | 10.57031 | 12.83203 | 11.86719 | 12.58203 |
| 50000 | 13.36719 | 19.13672 | 14.58203 | 16.59766 |
| 100000 | 15.84375 | 27.03125 | 15.56641 | 19.82422 |
| 200000 | 29.44922 | 40.51953 | 16.83203 | 25.68359 |
| 500000 | 50.52734 | 60.5 | 18.67578 | 24.97266 |
| 1000000 | 86.64063 | 105.9297 | 22.80859 | 35.58984 |
| 2000000 | 155.6563 | 203.5977 | 22.83594 | 56.76563 |
| 5000000 | 391.207 | 474.2734 | 35.17188 | 115.2852 |
| 10000000 | 771.125 | 936.5156 | 55.85156 | 216.0703 |
********************************************************************
字符串为【臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。】
********************************************************************
| 10 | 10.58594 | 8.902344 | 9.027344 | 9.0625 |
| 100 | 9.0625 | 9.0625 | 9.0625 | 9.0625 |
| 1000 | 9.0625 | 9.0625 | 9.0625 | 9.0625 |
| 10000 | 11.09766 | 14.29688 | 13.77734 | 14.18359 |
| 20000 | 14.18359 | 19.70313 | 14.42578 | 15.14063 |
| 50000 | 19.75 | 27.85547 | 14.89844 | 16.91016 |
| 100000 | 35.87109 | 42.65234 | 15.58984 | 19.85156 |
| 200000 | 54.32422 | 71.60547 | 17.05859 | 25.91016 |
| 500000 | 127.8242 | 137.7461 | 18.94531 | 25.24219 |
| 1000000 | 242.6445 | 262.5938 | 23.42969 | 36.21094 |
| 2000000 | 464.4609 | 514.0898 | 24.39063 | 58.32031 |
| 5000000 | 1146.625 | 1235.301 | 38.19141 | 118.3047 |
| 10000000 | 2291.086 | 2459.48 | 61.78516 | 222.0898 |