哈希表 粗浅理解

哈希表是什么?存在的意义在哪里?
哈希表是一张表,什么是表?
假设班上有50个人,成绩表,座位号排序,姓名,性别,成绩
编程上可以用一个一维数组表示,数组元素为一个指针,指向该学生信息的结构体
struct Score * arr[50];
这就是表,当你想知道班里21号同学的成绩时,只需要定位到表里第21行,代码里只需要访问数组元素arr[21-1]。
但是通常情况下,我们并不清楚班里所有人的座位号,假如我想知道班里王小刚的成绩,我不得不遍历这张成绩表,直到找到王小刚这个名字(这里假设座位号排序和人名没有关系),代码里也得遍历整个arr数组。
这时有人会想:我能不能以人名为索引建一张表,这样我想找王小刚的成绩,直接访问arr[王小刚]就能找到;
想法很好,但是我们知道数组的下标是整数,不能这么使用。
那该怎么办呢?
他又想了想说:我写一个函数,实现映射人名到数组下标,这样我只要输入人名就能得到数组下标,进而快速的找到这个人的成绩;
这个人写了下面这段伪代码(字符串不能用于switch,但意思就是这个意思),他说我找王小刚的成绩不需要遍历整张表,而只需要一步操作,那就是arr[mapping(王小刚)]。

int mapping(string name)
{
switch(name) {

case 王小刚: return 20; break;

}
}

这个人想的以人名为索引建表、人名映射到数组下标的想法和哈希表的建立思路如出一辙。
哈希表就是一种为了快速定位查找而存在的一种数据结构。

哈希表查找过程:通过哈希函数(mapping),把关键字(王小刚)映射到存储数组的下标(20),再通过访问该数组元素快速查找数据(成绩)。

哈希表建立:假设我们用哈希表来存储上面的成绩表;
每一个学生有姓名、各科的成绩等信息,所以建一个结构体来表示,我们把这个结构体的类型名记为 Score_t;
typedef struct Score_t{
struct score_t* next;
string name;
int score1;
int score2;

}Score_t;
我们用一维数组来做表,元素为指向结构体的指针;Score_t *arry[];
接下来我们要把每个学生的结构体放在arry[]里面,存放的位置要跟我们的映射函数挂钩,这里我们的映射函数定为学生姓名首字母大写的ascII码相加,然后对100取余;以小刚为例,mapping(王小刚) 就等于return (‘W’+‘X’+‘G’)%100; 等于46,那就把arry[46]指向王小刚;这样我们要找王小刚便只需要调用arry[mapping(“王小刚”)],不需要遍历整张成绩表,时间复杂度只有O(1);

哈希冲突:基于上面那个映射函数mapping,如果班里有以为同学名字叫王晓光,他的首字母’W’‘X’'G’和王小刚一样,所以映射的数组下标也一样,是46,冲突就产生了。一般有2种方法解决冲突。
1、修改映射函数
2、将小刚结构体里的指针指向晓光

冲突查找
当数据多起来的时候,我们几乎不可能找到一个实现无冲突的映射函数。假设我们用上面的第二种方法解决冲突,那么哈希表中就有一个这样的链表:arry[46] -> 小刚 -> 晓光。 所以在查找的时候就应该遍历这个链表,看看哪一个是目标。比如要找晓光,就会定位到array[46],然后遍历链表,先找到小刚,对比小刚和晓光的名字,不一样;找下一个节点晓光,对比晓光和晓光的名字,一样,找到,退出遍历。

你可能感兴趣的:(数据结构)