一、Hashtable(哈希表)
1. 基本概念
-
非泛型集合:存储键值对(
object
类型),通过哈希算法实现快速查找。 -
线程安全:默认非线程安全,可通过
Hashtable.Synchronized
创建线程安全版本。 -
键的唯一性:键必须唯一,且不可为
null
(值可为null
)。
2. 创建与初始化
// 创建空的 Hashtable
Hashtable hashtable = new Hashtable();
// 创建并初始化
Hashtable table = new Hashtable() {
{ 0, "这是0" },
{ "1", "这是1" },
{ true, "这是true" },
{ 'a', "aaaa" }
};
3. 常用属性与方法
操作 | 代码示例 | 说明 |
---|---|---|
添加键值对 | table.Add(123, "123"); | 添加键值对(键不存在时)。 |
通过键访问值 | string value = (string)table[true]; | 通过键获取值(返回 object ,需强制类型转换)。 |
通过键设置值 | table['a'] = "new value"; | 修改已存在键对应的值。 |
判断键是否存在 | bool hasKey = table.ContainsKey(0); | 检查是否包含指定键。 |
判断值是否存在 | bool hasValue = table.ContainsValue("123"); | 检查是否包含指定值。 |
删除键值对 | table.Remove(true); | 删除指定键对应的元素。 |
清空哈希表 | table.Clear(); | 移除所有键值对。 |
获取元素数量 | int count = table.Count; | 返回哈希表中键值对的数量。 |
获取所有键 | ICollection keys = table.Keys; | 返回所有键的集合。 |
获取所有值 | ICollection values = table.Values; | 返回所有值的集合。 |
4. 遍历 Hashtable
// 遍历所有键值对
foreach (DictionaryEntry entry in table) {
Console.WriteLine($"Key: {entry.Key}, Value: {entry.Value}");
}
// 单独遍历键或值
foreach (var key in table.Keys) {
Console.WriteLine(key);
}
foreach (var value in table.Values) {
Console.WriteLine(value);
}
5. 注意事项
-
装箱拆箱:由于存储
object
类型,值类型(如int
、bool
)会发生装箱拆箱,影响性能。 -
键的哈希码:键必须正确实现
GetHashCode()
和Equals()
方法,否则可能无法正确查找。 -
无序性:遍历时元素顺序不确定,不保证与添加顺序一致。
二、SortedList(排序列表)
1. 基本概念
-
非泛型集合:存储键值对,且按键自动排序(升序)。
-
双重索引:支持通过键(如
sortedList[10]
)或索引位置(如sortedList.GetByIndex(0)
)访问。 -
内存优化:内部使用数组实现,适合静态数据(插入 / 删除频繁时性能较差)。
2. 创建与初始化
// 创建空的 SortedList
SortedList sortedList = new SortedList();
// 创建并初始化
SortedList list = new SortedList() {
{ 10, "这是10" },
{ 6, "这是6" },
{ 5, "这是5" },
{ 3, "这是3" }
};
// 注意:键必须可比较(实现 IComparable 接口),否则会报错(如混合数值和字符类型)
3. 常用属性与方法
操作 | 代码示例 | 说明 |
---|---|---|
添加键值对 | list.Add(1, "这是1"); | 添加键值对(键不存在时)。 |
通过键访问值 | string value = (string)list[10]; | 通过键获取值(返回 object ,需强制类型转换)。 |
通过索引访问值 | string value = (string)list.GetByIndex(0); | 通过索引位置获取值(索引按升序排列)。 |
通过索引访问键 | object key = list.GetKey(0); | 获取指定索引位置的键。 |
修改值 | list[10] = "新值"; | 通过键修改对应的值。 |
删除键值对 | list.Remove(10); | 删除指定键对应的元素。 |
删除指定索引 | list.RemoveAt(0); | 删除指定索引位置的元素。 |
清空列表 | list.Clear(); | 移除所有键值对。 |
获取元素数量 | int count = list.Count; | 返回列表中键值对的数量。 |
获取所有键 | ICollection keys = list.Keys; | 返回所有键的集合(按键升序排列)。 |
获取所有值 | ICollection values = list.Values; | 返回所有值的集合(按对应键的升序排列)。 |
4. 遍历 SortedList
// 遍历所有键值对(按键升序)
foreach (DictionaryEntry entry in list) {
Console.WriteLine($"Key: {entry.Key}, Value: {entry.Value}");
}
// 通过索引遍历
for (int i = 0; i < list.Count; i++) {
Console.WriteLine($"Index: {i}, Key: {list.GetKey(i)}, Value: {list.GetByIndex(i)}");
}
5. 注意事项
-
键的可比较性:键必须实现
IComparable
接口(如int
、string
等),否则会抛出异常。 -
性能特点:插入 / 删除操作较慢(O (n)),但查找效率高(O (log n))。
-
索引与键的区别:索引从 0 开始,按升序排列的键顺序分配;而键是用户自定义的。
三、Hashtable 与 SortedList 的对比
特性 | Hashtable | SortedList |
---|---|---|
排序 | 无序 | 按键升序排序 |
数据结构 | 哈希表(散列表) | 数组(双重索引) |
查找效率 | O (1)(平均) | O(log n) |
插入 / 删除 | O (1)(平均) | O (n)(需移动元素) |
内存占用 | 较高(需维护哈希表) | 较低(仅数组) |
键类型要求 | 需正确实现 GetHashCode() | 需实现 IComparable 接口 |
线程安全 | 默认非线程安全 | 默认非线程安全 |
推荐场景 | 快速查找,无需排序 | 需按键排序,且插入 / 删除较少 |
四、代码补充建议
1. Hashtable 补充
// 线程安全的 Hashtable
Hashtable syncTable = Hashtable.Synchronized(new Hashtable());
// 安全添加(避免键已存在的异常)
if (!table.ContainsKey(123)) {
table.Add(123, "123");
}
// 安全获取值(避免键不存在的异常)
object value;
if (table.ContainsKey(0)) {
value = table[0];
}
2. SortedList 补充
// 使用泛型版本 SortedList<TKey, TValue>(类型安全,无需装箱拆箱)
SortedList<int, string> genericList = new SortedList<int, string> {
{ 10, "这是10" },
{ 6, "这是6" }
};
// 检查键是否存在
if (genericList.ContainsKey(10)) {
Console.WriteLine(genericList[10]);
}
// 添加或更新值
if (genericList.ContainsKey(10)) {
genericList[10] = "更新的值";
} else {
genericList.Add(10, "新值");
}
五、注意事项
-
泛型替代方案:推荐使用
Dictionary<TKey, TValue>
(替代Hashtable
)和SortedList<TKey, TValue>
(替代非泛型SortedList
),以避免装箱拆箱。 -
性能权衡:
SortedList
在数据量大且插入 / 删除频繁时性能较差,可考虑使用SortedDictionary<TKey, TValue>
(基于红黑树,插入 / 删除效率为 O (log n))。 -
空引用检查:访问集合元素前建议检查
ContainsKey
或使用TryGetValu