110,539
社区成员
发帖
与我相关
我的任务
分享
Hashtable booklist=new Hashtable();
booklist.Add("vc",001);
booklist.Add("vb",002);
using System;
using System.Collections;
/* 哈希表简介
* 我不说些概念性的抽象知识,省得你晕
* Hashtable 类是 System.Collection 命名空间里定义的一个类
* 就像这个 ConsoleApplication78 命名空间里定义了类 lei1 一样
*
* 它内部有一个数组 bucket[] buckets,初始大小为 11(可修改),数组容量随着使用而增加,但容量一定是素数
* buckets 数组由 bucket 对象构成,bucket 类很小,很简单,只有三个成员变量
* int hash_coll; key 通过自身的 GetHashCode() 方法得到的哈希码,你不必关心它怎么算出来的,
* 只要知道不同的 key 有不同的哈希码,例如整数的哈希码等于自身的值
* 而 hash_coll 等于哈希码的低31位,只取低31位是因为第 32 位是标志位,另有他用
* 二进制比较糊涂的话,可以假设 hash_coll 值就是哈希码值,大多数情况是这样
* object key; 用户传入的键,装箱或转换为 object 对象存放在这个变量里
* object val; 用户跟键一起传入的值,装箱或转换为 object 对象存放
*
* 当用户存入键和值的时候,程序会根据key计算 hash_coll,并将 hash_coll,key,val 组成 bucket 对象,存入数组 buckets。
*
* 问题之一: 11个元素的数组,当前 bucket 对象应该存入那个元素?
* 答: 根据 hash_coll 与数组容量 11 的余数来定位。例如 key 是整数 22,hash_coll = 22,22 % 11 = 0,所以存入 buckets[0]
* 问题之二: 余数冲突怎么办?例如 hash_coll 等于 0 或 22 时,余数都是 0
* 答: 容量不到 8 个是不会改变 11 这个容量的(默认 72% 是界限,可修改),遇到这种余数定位冲突,有个解决方法
* hash_coll 是个 32 位数字,最高位专门拿出来做标志位,说明当前 buckets 数组元素是否曾遇到过冲突的情况
* 这里我们先存入 key = 22 的,后存入 key = 0 的。发生冲突了 buckets[0] 的 hash_coll 最高位变为 1。
* 同时 key = 0 的 bucket 对象无法存入 buckets[0],而存入了 buckets[2],偏移量 2 是根据 key = 0 算出来的,这里不详述。
* 问题之三: 怎么提取已存入的元素?
* 答: 例如上述 0 和 22,提取的时候先计算余数,余数指向 buckets[0],找到 buckets[0] 的 key 进行比较是否相等,
* 如果提取 key = 22 的话,这就成了。如果提取 key = 0 的话,key 不相等,这时判断如果 buckets[0] 曾经冲突过,
* 就根据 0 算出偏移量 2,然后寻找 buckets[2],判断 key 相等,完成。如果不相等并且有冲突,还可以寻找 buckets[4]...
* 问题之四: 这种机制的好处?
* 答: 哈希表主要用于查找,理想情况下哈希表没有冲突,根据 key 第一时间找到值,就像数组一样,例如上述依次存入 key 为 0 到 6 的键/值对的情况。
* 但容量设为 11 等小数字,就会造成了冲突的发生,存入和提取键/值对都要多次寻址,但相对于节省的空间来说,很上算了,因为冲突概率较小
* 注意: 自定义类要重写GetHashCode()方法才能用作key存入哈希表,否则可能会造成哈希表key崩溃。
* 重写GetHashCode()方法后,必须同步重写Equals()方法。使哈希码相等条件和自定义类相等条件相同,否则也会有可能造成哈希表key崩溃。
*/
namespace ConsoleApplication78
{
class Program
{
static void Main()
{
// 初始化一个哈希表对象 booklist
Hashtable booklist = new Hashtable();
// 生成两个对象
lei1 lei01 = new lei1("vc", 001);
lei1 lei02 = new lei1("vb", 002);
// key最好是同一类型的值,否则有可能造成key崩溃
booklist.Add(001,lei01.name);
booklist.Add(002,lei02.isdn);
// 要输出全部值,最好这么写
foreach (DictionaryEntry d in booklist)
Console.WriteLine(d.Value);
}
class lei1
{
public string name;
public int isdn;
public lei1(string x, int y)
{
name = x;
isdn = y;
}
}
}
}
// 我曾经编写过仿微软 Hashtable 的源代码,使根据微软源码反编译后写成的。
// 下载:http://download.csdn.net/source/305015
// 讨论:http://topic.csdn.net/u/20071209/17/0129568b-30d1-4c87-aaa2-804b8b2bacf6.html