非泛型集合和泛型集合的超级详解,源码阅读总结

ArrayList ,List

ArrayList 和 List 皆以不约束长度的集合类型 ,List比较ArrayList
就此中落实来讲除了泛型本质没有太大不一致。可是为幸免装箱拆箱难题,尽只怕选拔List

聚拢内部是由数组完毕,私下认可大小是4,但您选择无参构造函数构造实例时,内部数组大小是0,当您参预第多少个要素时,才扩大体积为4,添比索素时,如若开采内置数组大小远远不足,内置数组大小会扩大体量为原来的两倍,每叁次扩大容积都会重新开荒一个数组,拷贝旧数组的多寡,如若您要给集结增多大量的要素却不为它起首化多个得体容积,频仍的内部存款和储蓄器开拓和剩下的数组拷贝会招致品质的开销。

为此选择时提出提供方便的体量。

C#非泛型集结和泛型集合的特级详细解释,

C# 泛型集结之非泛型集结类与泛型集合类的附和:

ArrayList对应List

HashTable对应Dictionary

Queue对应Queue

Stack对应Stack

SortedList对应SortedList

 

先是  : ArrayList(非泛型集结)  与List(泛型集结)

ArrayList 是数组的复杂性版本。ArrayList 类提供在大多 Collections
类中提供但不在 Array 类中提供的黄金时代部分成效:

1.Array 的体积是固定的,而 ArrayList 的体量是基于必要活动扩张的。

2.ArrayList 提供丰裕、插入或移除某大器晚成节制作而成分的格局。在 Array
中,您一定要一遍拿走或设置叁个成分的值。

3.使用 Synchronized 方法能够超轻易地创建 ArrayList 的一块版本。而 Array
将一向维系它直到顾客实现协作截止。

4.ArrayList 提供将只读和永远大小包裹重回到聚集的方法。而 Array 不提供。

5.Array 提供 ArrayList 所不持有的一些灵活性:

   a.可以安装 Array 的下限,但 ArrayList 的下限始终为零。

   b.Array 能够有所四个维度,而 ArrayList 始终只是生机勃勃维的。

   c.特定类型(不包括 Object卡塔 尔(阿拉伯语:قطر‎的 Array 的性能比 ArrayList 好,那是因为
ArrayList 的成分归属 Object
类型,所以在蕴藏或索求值类型时常常产生装箱和注销装箱。

   d.必要一个数组的大多数情形也足以代之以使用
ArrayList。它更便于使用,并且普通具有与 Object 类型的数组雷同的属性。

6.Array 坐落 System 命名空间中;ArrayList 位于 System.Collections
命名空间中。

ArrayList类对象方法:

1:Add()向数组中增多二个要素,
2:Remove()删除数组中的三个要素
3:(int i)删除数组中索引值为i的要素
4:Reverse()反转数组的要素
5:Sort()以从小到大的顺序排列数组的要素
6:Clone()复制三个数组

一:ArrayList:

ArrayList能够不要钦点维数 可动态赋值  赋区别类型值

 

ArrayList arrayList1 = new ArrayList();
             arrayList1.
             arrayList1.Add("a");
             arrayList1.Add(1);
             arrayList1.Add("b");
             Response.Write(arrayList1[1]);

二:Array:

Array的体积是定位的 先钦命大小 在赋值

 

 Array arrayList2 = Array.CreateInstance(typeof(string), 6);
             arrayList2.SetValue("a", 0);
             arrayList2.SetValue("b", 1);
             Response.Write(arrayList2.GetValue(1));

List泛型集结:

泛型集结List<T>
  泛型最关键的选择正是谋面操作,使用泛型集结可以抓实代码重用性,类型安全和更佳的个性。
  List<T>的用法和ArrayList近似,List<T>有越来越好的品类安全性,无须拆,装箱。
在泛型定义中,泛型类型参数“<T>”是必得钦赐的,此中T是概念泛型类时的占位符,其并不是风流倜傥种档案的次序,仅表示某种大概的品类。在概念时T会被选取的类型代替。泛型集结List<T>中只好有三个参数类型,“<T>”中的T能够对聚集中的成分类型进行节制。

eg:
List<T>增加、删除、检索成分的情势和ArrayList雷同,鲜明的特色是不必要像ArrayList那样装箱和拆箱。

List < Student > students = new List < Student > ();
   Student stu1 = new Student();
   stu1.Name = "陆小凤";
   stu1.Number = "0801";
   stu1.Score = 20;
   Student stu2 = new Student();
   stu2.Name = "西门吹雪";
   stu2.Number = "0802";
   stu2.Score = 23;
   students.Add(stu1);
   students.Add(stu2);
   Console.WriteLine("集合中的元素个数为{0}", students.Count);
   foreach (Student stu in students)
   {
    Console.WriteLine("/t{0}/t{1}/t{2}", stu.Name, stu.Number, stu.Score);
   }
   students.Remove(stu1);
   Console.WriteLine("集合中的元素个数为{0}", students.Count);
   Console.ReadLine();

List<T>和ArrayList的区别
     
List<T>和ArrayList的肖似点:添欧成分、删除成分、通过索引访谈成分方法相仿。
  List<T>和ArrayList的分歧点:
ArrayList能够加上放肆等级次序成分;List<T>对增进的成分具备类型约束;
ArratList增添服装箱,读取时拆箱;List<T>无需装箱,拆箱操作;

//创建Person对象
   Person p1 = new Person("张三", 30);
   Person p2 = new Person("李四", 20);
   Person p3 = new Person("王五", 50);
   //创建类型为Person的对象集合
   List < Person > persons = new List < Person > ();
   //将Person对象放入集合
   persons.Add(p1);
   persons.Add(p2);
   persons.Add(p3);
   //输出第2个人的姓名
   Console.WriteLine(persons[1].Name);
   foreach (Person p in persons)
   {
    Console.WriteLine("/t{0}/t{1}", p.Name, p.Age);
   }

其次 :HashTable(非泛型集结)对应Dictionary(泛型集结卡塔尔

Hashtable 和 Dictionary <K, V> 类型

 1:单线程程序中引用使用 Dictionary, 有泛型优势, 且读取速度极快,
体积利用更充裕.
 2:十二线程程序中援用应用 Hashtable, 暗中同意的 Hashtable 允许单线程写入,
三十二线程读取, 对 Hashtable 进一层调用 Synchronized()
方法能够博得完全线程安全的类型. 而 Dictionary 非线程安全, 必需人为使用
lock 语句举办保险, 功能大减.
 3:Dictionary 有按插入顺序排列数据的特点 (注: 但当调用 Remove()
删除过节点后相继被打乱), 因而在须求反映顺序的境地中央银行使 Dictionary
能获取一定方便.

Hashtable 类和 Dictionary<(Of <(TKey, 电视alue>)>) 泛型类实现IDictionary 接口

Dictionary<(Of <(TKey, 电视机alue>)>) 泛型类还落实IDictionary<(Of <(TKey, TValue>)>)
泛型接口。因而,那一个聚聚集的每一个成分都以二个键/值对。

Dictionary<(Of <(TKey, TValue>)>) 类与 Hashtable
类的效用周围
对于值类型,特定项目(不包涵 Object卡塔尔国的 Dictionary<(Of <(TKey,
TValue>)>) 的质量优于 Hashtable,那是因为 Hashtable 的要素归属Object 类型,所以在存款和储蓄或研究值类型时日常产生装箱和注销装箱操作。

eg:

HashTable ht=new HashTable();//实现 IDictionary接口
ht.Add(1,"A");
 ht.Add(2,"B");
 ht.Add(3,"c");
 foreach(DictionaryEntry de in ht)//HashTable返回的是DictionaryEntry类型
 {
     de.Key;
     de.Value;
  }

Dictionary<int,string> myDictionary=new Dictionary<int,string>();//实现IDictionary接口,IDictionary<T key,T value>类
myDictionary.Add(1,"a");
 myDictionary.Add(2,"b");
 myDictionary.Add(3,"c");
 foreach(int i in myDictionary.Keys)
{
   Console.WriteLine("Key="+i+"Value="+myDictionary);
 }
 Or
 foreach(KeyValuePair<string, double> temp in myDictionary)//返回的是KeyValuePair<string, double>泛型数组
  {
        temp.Key;
        temp.Value;
   }

一:HashTable:

1.HashTable是大器晚成种散列表,他里头维护广大对Key-Value键值对,其还也可以有多少个相近索引的值叫做散列值(HashCode),它是基于GetHashCode方法对Key通过自然算法获取获得的,全数的搜寻操作定位操作都以依附散列值来贯彻找到呼应的Key和Value值的。

2.咱们要求运用一个算法让散列值对应HashTable的长空地址尽量不另行,那正是散列函数(GetHashCode)要求做的事。

3.当二个HashTable被挤占半数以上的时候大家因而测算散列值获得的地点值大概会再次指向同意气风发地方,那正是哈希冲突。

4.在.Net中键值对在HashTable中的地点Position= (HashCode& 0x7FFFFFFF) %
HashTable.Length,.net中是因而探测法清除哈希冲突的,当通过散列值得到的职位Postion甚至被占用的时候,就能够增添多少个位移x值决断下一个岗位Postion+x是或不是被占用,如若照旧被占用就持续往下位移x判别Position+2*x地点是或不是被占用,若无被并吞则将值放入在那之中。当HashTable中的可用空间更加的时辰,则收得到到可用空间的难度更大,消耗的光阴就越来越多。

5..脚下HashTable中的被占用空间到达八个百分比的时候就将该空间活动扩大体积,在.net中那个比例是72%,也叫.net中HashTable的填写因子为0.72。比方有叁个HashTable的空中山大学小是100,当它必要充裕第71个值的时候将会扩大体量此HashTable.

6.以此活动扩大体积的高低是稍稍吗?答案是日前空间大小的两倍最临近的素数,比方当前HashTable所占空间为素数71,假如扩大体量,则扩大体积大小为素数131.

图片 1

二:Dictionary

1.Dictionary是生龙活虎种变种的HashTable,它使用豆蔻梢头种分离链接散列表的数据结构来消除哈希冲突的主题材料。

2.剥离链接散列表是当散列到同三个地址的值存为多个链表中。

3.以此变种HashTable的填写因子是1

图片 2

eg:本文将以代码的情势探究HashTable和Dictionary的插入和三种读取格局的频率(for/foreach/GetEnumerator)

public class HashTableTest

    {

        static Hashtable _Hashtable;

        static Dictionary<string, object> _Dictionary;

        static void Main()

        {

            Compare(10);

            Compare(10000);

            Compare(5000000);

            Console.ReadLine();

        }

        public static void Compare(int dataCount)

        {

            Console.WriteLine("-------------------------------------------------n");

            _Hashtable = new Hashtable();

            _Dictionary = new Dictionary<string, object>();

            Stopwatch stopWatch = new Stopwatch();

            //HashTable插入dataCount条数据需要时间

            stopWatch.Start();

            for (int i = 0; i < dataCount; i++)

            {

                _Hashtable.Add("Str" + i.ToString(), "Value");

            }

            stopWatch.Stop();

            Console.WriteLine(" HashTable插入" + dataCount + "条数据需要时间:" + stopWatch.Elapsed);



            //Dictionary插入dataCount条数据需要时间

            stopWatch.Reset();

            stopWatch.Start();

            for (int i = 0; i < dataCount; i++)

            {

                _Dictionary.Add("Str" + i.ToString(), "Value");

            }

            stopWatch.Stop();

            Console.WriteLine(" Dictionary插入" + dataCount + "条数据需要时间:" + stopWatch.Elapsed);



            //Dictionary插入dataCount条数据需要时间

            stopWatch.Reset();

            int si = 0;

            stopWatch.Start();

            for(int i=0;i<_Hashtable.Count;i++)

            {

                si++;

            }

            stopWatch.Stop();

            Console.WriteLine(" HashTable遍历时间:" + stopWatch.Elapsed + " ,遍历采用for方式");



            //Dictionary插入dataCount条数据需要时间

            stopWatch.Reset();

            si = 0;

            stopWatch.Start();

            foreach (var s in _Hashtable)

            {

                si++;

            }

            stopWatch.Stop();

            Console.WriteLine(" HashTable遍历时间:" + stopWatch.Elapsed + " ,遍历采用foreach方式");



            //Dictionary插入dataCount条数据需要时间

            stopWatch.Reset();

            si = 0;

            stopWatch.Start();

            IDictionaryEnumerator _hashEnum = _Hashtable.GetEnumerator();

            while (_hashEnum.MoveNext())

            {

                si++;

            }

            stopWatch.Stop();

            Console.WriteLine(" HashTable遍历时间:" + stopWatch.Elapsed + " ,遍历采用HashTable.GetEnumerator()方式");



            //Dictionary插入dataCount条数据需要时间

            stopWatch.Reset();

            si = 0;

            stopWatch.Start();

            for(int i=0;i<_Dictionary.Count;i++)

            {

                si++;

            }

            stopWatch.Stop();

            Console.WriteLine(" Dictionary遍历时间:" + stopWatch.Elapsed + " ,遍历采用for方式");



            //Dictionary插入dataCount条数据需要时间

            stopWatch.Reset();

            si = 0;

            stopWatch.Start();

            foreach (var s in _Dictionary)

            {

                si++;

            }

            stopWatch.Stop();

            Console.WriteLine(" Dictionary遍历时间:" + stopWatch.Elapsed + " ,遍历采用foreach方式");



            //Dictionary插入dataCount条数据需要时间

            stopWatch.Reset();

            si = 0;

            stopWatch.Start();

            _hashEnum = _Dictionary.GetEnumerator();

            while (_hashEnum.MoveNext())

            {

                si++;

            }

            stopWatch.Stop();

            Console.WriteLine(" Dictionary遍历时间:" + stopWatch.Elapsed + " ,遍历采用Dictionary.GetEnumerator()方式");





            Console.WriteLine("n-------------------------------------------------");

        }

    }

 四:从地方的结果能够看见

1.HashTable大数据量插入数据时索要开支比Dictionary大的多的日子。

2.for方法遍历HashTable和Dictionary速度最快。

3.在foreach方式遍历时Dictionary遍历速度越来越快。

五:在单线程的时候使用Dictionary越来越好有的,多线程的时候利用HashTable越来越好。

因为HashTable能够通过Hashtable tab = Hashtable.Synchronized(new
Hashtable());拿到线程安全的靶子。

eg: hashtable

 public static Hashtable List()
        {
            Hashtable h = new Hashtable();
            h.Add(1,"asdasdsad");
            h.Add("dasda","dsadsa");
            return h;
        }


Hashtable list=List();
            foreach(Object item in list.Keys){
                Console.WriteLine(item);
                Console.WriteLine(list[item]);
            }

三:遍历情势:

Dictionary的三种遍历方式:

Dictionary<string, int> list = new Dictionary<string, int>();

           list.Add("d", 1);
//一:通过key值遍历:
foreach (string key in list.Keys) {
         Console.WriteLine(key + list[key]);
   }
//二:通过value值遍历:
foreach (int val in list.Values){
         Console.WriteLine(val);
   } 
//三:通过key和value遍历:
foreach (KeyValuePair<string, int> kv in list){
         Console.WriteLine(kv.Key + kv.Value);
   }
//四:3.0以上版本
foreach (var item in list){
         Console.WriteLine(item.Key + item.Value);
   }

HashTable的遍历方式:

static void Main(string[] args)
 2         {
 3             Person person1 = new Person();
 4             person1.Age = 34;
 5             person1.Name = "Jacky";
 6             person1.Email = "[email protected]";
 7 
 8             Person person2 = new Person();
 9             person2.Age = 23;
10             person2.Name = "Ajay";
11             person2.Email = "[email protected]";
12 
13             Person person3 = new Person();
14             person3.Age = 12;
15             person3.Name = "Bill";
16             person3.Email = "[email protected]";
17 
18             Person person4 = new Person();
19             person4.Age = 23;
20             person4.Name = "Gace";
21             person4.Email = "[email protected]";
22 
23             Person person5 = new Person();
24             person5.Age = 45;
25             person5.Name = "Jim";
26             person5.Email = "[email protected]";
27 
28             Hashtable ht = new Hashtable();
29             ht.Add("1", person1);
30             ht.Add("2", person2);
31             ht.Add("3", person3);
32             ht.Add("4", person4);
33             ht.Add("5", person5);
34             Console.WriteLine("请输入你的查询的用户名:");
35             string strName = Console.ReadLine();
36             //第一种方法 key值
37              foreach (string item in ht.Keys)
38             {
39                 Person p = (Person)ht[item];
40                 if (strName == p.Name)
41                 {
42                     Console.WriteLine("查询后的结果是:" + p.Name + "t" + p.Email + "t" + p.Age);
43                 }
44             }
45 
46 
47 
48             //第二种方法 value值
49              foreach (Person item in ht.Values)
50             {
51                 if (item.Name == strName)
52                 {
53                     Console.WriteLine("查询后的结果是:" + item.Name + "t" + item.Email + "t" + item.Age);
54                 }
55 
56             }
57             //第三种方法 key和value值
58              foreach (DictionaryEntry item in ht)
59             {
60                 if (strName == ((Person)item.Value).Name)
61                 {
62                     Console.WriteLine("查询后的结果是:" + ((Person)item.Value).Name + "t" + ((Person)item.Value).Email + "t" + ((Person)item.Value).Age);
63                 }
64             }
65 
66             //第四种方法
67              IDictionaryEnumerator id = ht.GetEnumerator();
68             while (id.MoveNext())
69             {
70              Person p =   (Person)ht[id.Key];
71              if (p.Name == strName)
72              {
73                  Console.WriteLine("查询后的结果是:" + p.Name + "t" + p.Email + "t" + p.Age);
74              }
75             }
76 
77         }

 第四:Queue集合和Stack

Queue:它是二个先进先出的聚众(它存款和储蓄于队列中卡塔尔国,先进先出的情趣也正是第黄金时代放进集结的数量,拿多少的时候从中期放进去的数目起先拿。

Stack:它是三个后进先出的联谊(它存款和储蓄于栈中卡塔 尔(阿拉伯语:قطر‎,后进先出的意思从名称想到所富含的意义,也等于说取多少只可以从最后放进去的要命数据开头取。

 以下代码实例了个别选用Stack和Queue打字与印刷数字0~9。

//写入数据到Queue中
2. Queue q = new Queue();
3. for (int i = 0; i < 10; i++)
4. {
5.     q.Enqueue(i);
6. }
7. 
8. 
9. //循环输出Queue所有数据
10. Console.WriteLine("开始输出Queue数据");
11. while (q.Count > 0)
12. {
13.     Console.WriteLine(q.Dequeue());
14. } 
15. 
16. //-------------------------------------分割线------------------------------------//
17. 
18. //写入数据到Stack中
19. Stack s = new Stack();
20. for (int i = 0; i < 10; i++)
21. {
22.     s.Push(i);
23. }
24. 
25. //循环输出所有Stack数据
26. Console.WriteLine("开始输出Stack数据");
27. while (s.Count > 0)
28. {
29.     Console.WriteLine(s.Pop());
30. }

输出结果:
图片 3

基于以下代码对Queue 与
Stack实行了品质测验,他们的属性都比数组要伟大致2~倍。

Stopwatch sw_queue = new Stopwatch();
2. sw_queue.Start();
3. 
4. //写入数据到Queue中
5. Queue q = new Queue();
6. for (int i = 0; i < 1000000; i++)
7. {
8.     q.Enqueue(i);
9. }
10. 
11. //循环输出Queue所有数据
12. while (q.Count > 0)
13. {
14.     q.Dequeue();
15. }
16. 
17. sw_queue.Stop(); // 停止监视
18. Console.WriteLine("Queue 100万数据写入读取消耗时间:{0}毫秒", sw_queue.Elapsed.TotalMilliseconds.ToString());
19. 
20. //---------------------------------分割线--------------------------------//
21. 
22. Stopwatch sw_stack = new Stopwatch();
23. sw_stack.Start();
24. 
25. 
26. //写入数据到Stack中
27. Stack s = new Stack();
28. for (int i = 0; i < 1000000; i++)
29. {
30.     s.Push(i);
31. }
32. 
33. //循环输出所有Stack数据
34. while (s.Count > 0)
35. {
36.     s.Pop();
37. }
38. 
39. sw_stack.Stop(); // 停止监视
40. Console.WriteLine("Stack 100万数据写入读取消耗时间:{0}毫秒", sw_stack.Elapsed.TotalMilliseconds.ToString());
41. 
42. 
43. Console.R
eadKey();

测量检验结果:
图片 4

Queue 的重视成员:

属性  

Count    //元素数     

方法 

Clear()   //清空 

Contains() //是还是不是含有 

Dequeue() //出列 

Enqueue() //入列 

Peek()   //获取就要出列的 

Stack 的首要成员:

属性   Count       //     

方法 

Clear()      // 

Contains()    // 

Peek()       //获取就要出栈的 

Pop()       //出栈 

Push()       //压栈 

第五:SortedList

hashtable,Dictionary

hashtable和Dictionary都以哈希表的得以完成,超多个人说Dictionary内部是由hashtable达成的,那是不对劲的。

hashtable的结构须求装载因子,装载因子是0.1 到 1.0 范围内的数字
,是中间存款和储蓄桶数(count卡塔尔所占桶数组(buckets卡塔尔国桶数(hashsize卡塔尔国的最大比率
,当桶数大于装载数(loadsize卡塔 尔(阿拉伯语:قطر‎时,桶数组就能够扩大体积

hashtable内部排除哈希冲突的算法是再次散列法,是开放地点法中最佳的艺术之风流倜傥

而各异的是,Dictionary内部消除哈希冲突的算法是链地址法,况且Dictionary的组织不必要装载因子,不受装载因子的限制,若是Dictionary一点都一点都不大,查找,插入,删除等操作具备形似O(1卡塔尔的功能

和ArrayList
,List相似的是Dictionary和hashtable内部也是由数组达成的,所以组织时也需求提供方便体量,避免品质的消耗。

但大家必要别的注意的是您提要求构造函数的体量不必然会是始于时放置数组的尺寸,构造函数内部会接纳二个压倒等于你所筛选体积的素数作为忠实的领头体积。

1、SortedList定义

System.Collections.SortedList类表示键/值对的汇集,那几个键值对开关排序并可依据键和目录访问。SortedList
在个中维护三个数组以存款和储蓄列表中的成分;即,二个数组用于键,另四个数组用于相关联的值。每一种成分都以贰个可用作
DictionaryEntry 对象开展走访的键/值对。键无法为null,但值能够。

HashSet

HashSet是二个严节的能够保持唯豆蔻梢头性的聚焦。我们也得以把HashSet看作是Dictionary<TKey,TValue>,只但是TKey和电视机alue都针对同三个指标。内部落实和Dictionary特别相仿。
HashSet特别契合在我们须要保险集合内成分唯风姿罗曼蒂克性但又不供给按顺序排列的时候。

2.优点

1、SortedList
允许通过有关联键或通过索引对值进行访谈,可提供越来越大的左右逢原。

2、可依靠须求活动叠合体量。

发表评论

电子邮件地址不会被公开。 必填项已用*标注