哈希表:
Hashtable. (也叫散列表) 无序.
哈希表 (Hashtable) HashSet.
由一对 (key , value) 类型的元素组成的集合.
所有元素的 key 必须唯一.
key ->value 是一对一的映射, 即根据 key 就可以立刻在集合中找到所需元素.
Hashtable 方法:
Add(key, value)
根据 key 而不是根据索引查找, 因此速度很快
例子:
为哈希表追加不重复的 100 个值, 且每个值都是 1-100 之间的随机数, 问哪个数字重复的次数最多, 重复了多少次?
集合的迭代器
迭代器提供了对集合统一的遍历方案
foreach 的本质:
注意: 1. 禁止在迭代中修改迭代变量!!!
2. 禁止在迭代中修改集合!!!
数组和集合的比较:
1. 数组声明了元素类型, 但集合没有, 因为集合中所用元素都存储为对象.
2. 数组的大小是固定的, 不能增加和减少; 而集合类可根据需要动态调整大小
检索元素的方式不同.
装箱和拆箱:
1. 装箱在值类型向引用类型转换时发生
object obj = 1; 这行语句将整型常量 1 赋给 object 类型的变量 obj; 众所周知常量 1 是值类型, 值类型是要放在栈上的, 而 object 是引用类型, 它需要放在堆上; 要把值类型放在堆上就需要执行一次装箱操作.
以上就是装箱所要执行的操作了, 执行装箱操作时不可避免的要在堆上申请内存空间, 并将堆栈上的值类型数据复制到申请的堆内存空间上, 这肯定是要消耗内存和 CPU 资源的.
2. 拆箱在引用类型向值类型转换时发生
- object objValue = 4;
- int value = (int)objValue;
上面的两行代码会执行一次装箱操作将整形数字常量 4 装箱成引用类型 object 变量 objValue; 然后又执行一次拆箱操作, 将存储到堆上的引用变量 objValue 存储到局部整形值类型变量 value 中.
拆箱操作的执行过程和装箱操作过程正好相反, 是将存储在堆上的引用类型值转换为值类型并给值类型变量.
装箱操作和拆箱操作是要额外耗费 CPU 和内存资源的, 所以在 c# 2.0 之后引入了泛型来减少装箱操作和拆箱操作消耗.
泛型集合:
上面的情况是不带泛型的集合, 我们可以看到, 这种集合对象存储不易控制, 类型转换容易出错.
下面的是带泛型的集合:
从上面两种情况我们可看出:
泛型集合可以约束集合内的元素类型.
编译时检查类型约束.
无需装箱拆箱操作.
加上 using System.Collections.Generic;
List<T>,Dictionary<K,V> /<T>,<K,V > 表示该泛型集合中的元素类型.
List<Student> students = new List<Student>();
利用 List<Student > 存储班级集合.
面试题:
请简述 ArrayList 和 List<Int > 的主要区别:
1.ArrayList 不带泛型 数据类型丢失.
2.List<T> 带泛型 数据类型不丢失.
3.ArrayList 需要装箱拆箱 List<T > 不需要.
Dictionary<K,V > 具有 List<T > 相同的特性
<K,V > 约束集合中元素类型
编译时检查类型约束
无需装箱拆箱操作
与哈希表类似存储 Key 和 Value 的集合
泛型集合与传统集合相比类型更安全.
泛型集合无需装箱拆箱操作.
泛型的重要性:
1. 解决了很多需要繁琐操作的问题.
2. 提供了更好的类型安全性.
例子:
假定书籍的种类有 5 种, 设计何种的数据结构可以达到快速查询某类所有书籍的功能 (提示: 用 Dictionary<K,V>)
判断一篇英文文章出现了哪些字母, 以及每个字母出现的个数
链表:
LinkedList<T>
生成和追加 LinkedList<string> linked = new LinkedList<string>();
- linked.AddLast("cat");
- linked.AddLast("dog");
- linked.AddLast("man");
- linked.AddFirst("first");
查找和插入 LinkedListNode<T>
- LinkedListNode<string> node = linked.Find("one");
- linked.AddAfter(node, "inserted");
例子:
集合的排序:
集合中全部为对象类型.
所以集合需要排序的时候则必须两个对象需要有可比性.
IComparable 与 IComparer 接口
为了能够对数据项进行排序, 就要确定两个数据项在列表中的相对顺序, 也就是要确定两个对象的 "大小" 关系. 一般来说, 可以通过如下两种方式来定义大小关系.
第一种方式是针对对象本身. 为了使对象自己能够执行比较操作, 该对象必须实现 IComparable 接口, 即至少具有一个 CompareTo() 成员.
System.IComparable 接口中有如下方法:
int CompareTo(object obj);
它根据当前对象与要比较的对象的 "大小" 返回一个正数, 0 或一个负数.
第二种方式是提供一个外部比较器, 能够比较对象的大小, 并实现 IComparer 接口.
System.Collections.IComparer 接口中有如下方法:
int Compare(object obj1, object obj2);
它根据第一个对象与第二个对象的 "大小" 返回一个正数, 0 或一个负数.
许多类在进行排序和查找时, 都要求提供这样的外部比较器.
例子:
1. 通过 IComparable 来进行排序
实现接口
2. 通过 IComparer 来进行排序
来源: http://www.jianshu.com/p/35b90e71ada8