① 散列表的查找效率主要取决于建表时所选取的散列函数和处理冲突的方法
散列表的查找效益主要取决于建表示所选的散列函数和储蓄方式的这段换成这个是写三角函数的处理方法。
② 关于散列表,散列函数的两个问题。
散列表是一种数据结构,通过散列函数(也就是 hash 函数)将输入映射到一个数字,一般用映射出的数字作为存储位置的索引。数组在查找时效率很高,但是插入和删除却很低。而链表刚好反过来。设计合理的散列函数可以集成链表和数组的优点,在查找、插入、删除时实现 O(1) 的效率。散列表的存储结构使用的也是数组加链表。执行效率对比可以看下图 1.3:
散列表的主要特点:
将输入映射到数字
2.不同的输入产生不同的输出
3.相同的输入产生相同的输出
4. 当填装因子超过阈值时,能自动扩展。填装因子 = 散列表包含的元素数 / 位置总数,当填装因子 =1,即散列表满的时候,就需要调整散列表的长度,自动扩展的方式是:申请一块旧存储容量 X 扩容系数的新内存地址,然后把原内存地址的值通过其中的 key 再次使用 hash 函数计算存储位置,拷贝到新申请的地址。
5. 值呈均匀分布。这里的均匀指水平方向的,即数组维度的。如果多个值被映射到同一个位置,就产生了冲突,需要用链表来存储多个冲突的键值。极端情况是极限冲突,这与一开始就将所有元素存储到一个链表中一样。这时候查找性能将变为最差的 O(n),如果水平方向填充因子很小,但某些节点下的链表又很长,那值的均匀性就比较差。
③ 有一个表长为m的散列表,初始状态为空,现将n(n<m)个不同的关键码插入到散列表中,解决冲突的方法是用线
假设n个关键码的散列值均为x,那么:
插入第一个关键码时,检查x位置,结果为空,直接插入,探测次数为0;
插入第二个关键码时,检查x位置,结果不为空,采用线性探测法,继续探测x+1位置,结果为空,插入,探测次数为1;
……
插入第n个关键码时,x位置不为空,从x+1位置开始探测,直至探测到x+(n-1)位置时才为空(这里假设x+(n-1)<m),执行插入操作,探测次数为n-1次。
所以,总的探测次数是一个等差数列,首项为0,公差为1,项数为n,那么,总次数自然可以用等差数列的求和公式算出,即S=a1+n*(n-1)*b/2=0+n*(n-1)*1/2=n(n-1)/2。
④ 已知散列表长度为13,散列函数为H(key)=key % 11,处理冲突的方法为线性探测法
10%11=10 a[9]=10
8%11=8 a[7]=8
40%11=7 a[6]=40
27%11=5 a[4]=27
21%11=10
57%11=2 a[1]=57
46%11=2
23%11=1 a[0]=23
19%11=8
56%11=1
21和10冲突 且a[10]空 所以a[10]=21
46和57冲突 且a[2]空 所以 a[2]=46
19和8冲突 且a[8]空 所以 a[8]=19
56和23冲突 且a[1]、a[2]不空,a[3]空 a[3]=56
最后是23,57,46,56,27,空,40,8,19,10,21,空,空
查找成功的平均长度:6*1+3*2+1*3=15
查找不成功的平均长度:6+5+4+3+2+1+6+5+4+3+2+1=42
(4)散列表中解决冲突的两种方法是扩展阅读:
直接寻址法
例如:有一个从1到100岁的人口数字统计表,其中,年龄作为关键字,哈希函数取关键字自身。
数字分析法
有学生的生日数据如下:
年.月.日
75.10.03
75.11.23
76.03.02
76.07.12
75.04.21
76.02.15
经分析,第一位,第二位,第三位重复的可能性大,取这三位造成冲突的机会增加,所以尽量不取前三位,取后三位比较好。
平方取中法
取关键字平方后的中间几位为哈希地址。
折叠法
将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位)作为哈希地址,这方法称为折叠法。
例如:每一种西文图书都有一个国际标准图书编号,它是一个10位的十进制数字,若要以它作关键字建立一个哈希表,当馆藏书种类不到10,000时,可采用此法构造一个四位数的哈希函数。
除留余数法
取关键字被某个不大于哈希表表长m的数p除后所得余数为哈希地址。
H(key)=key MOD p (p<=m)
随机数法
选择一个随机函数,取关键字的随机函数值为它的哈希地址,即
H(key)=random(key),其中random为随机函数。通常用于关键字长度不等时采用此法。
若已知哈希函数及冲突处理方法,哈希表的建立步骤如下:
Step1.取出一个数据元素的关键字key,计算其在哈希表中的存储地址D=H(key)。若存储地址为D的存储空间还没有被占用,则将该数据元素存入;否则发生冲突,执行Step2。
Step2.根据规定的冲突处理方法,计算关键字为key的数据元素之下一个存储地址。若该存储地址的存储空间没有被占用,则存入;否则继续执行Step2,直到找出一个存储空间没有被占用的存储地址为止。
⑤ 散列表处理冲突的二次探测法,表长要求是满足4j+3的质数。但我在做题过程中发现有的表长不满足这一条
合理误差
⑥ 哈希查找的解决冲突
影响哈希查找效率的一个重要因素是哈希函数本身。当两个不同的数据元素的哈希值相同时,就会发生冲突。为减少发生冲突的可能性,哈希函数应该将数据尽可能分散地映射到哈希表的每一个表项中。解决冲突的方法有以下两种:
(1) 开放地址法
如果两个数据元素的哈希值相同,则在哈希表中为后插入的数据元素另外选择一个表项。
当程序查找哈希表时,如果没有在第一个对应的哈希表项中找到符合查找要求的数据元素,程序就会继续往后查找,直到找到一个符合查找要求的数据元素,或者遇到一个空的表项。
(2) 链地址法
将哈希值相同的数据元素存放在一个链表中,在查找哈希表的过程中,当查找到这个链表时,必须采用线性查找方法。
例3. 6是一个简单的哈希查找算法程序,你可以将它和本章结尾的有关代码一起编译连接成一个可执行程序。
例3.6一个简单的哈希查找算法程序
1: #include<stdlib.h>
2: #include<string.h>
3: #include list.h
4: #include hash.h
5:
6: #define HASH_SIZE 1024
7:
8: static listnode_t *hashTable[HASH_SIZE];
9:
10: void insert(const char * s)
11: {
12: listnode_t *ele = newNode((void * ) s)
13: unsigned int h = hash(s) % HASH_SIZE;
14:
15: ele->next = hashTable[h]
16: hashTable[h] = ele;
17: }
18:
19: void print (void)
20: {
21: int h;
22:
23: for (h = 0; h < HASH_SIZE; h++)
24: {
25: listnode_t * lp = hashTalbe[h];
26:
27: if(lp == NULL)
28: continue;
29: printf([%d] , h);
30: while (lp)
31: {
32: printf( '%s' , lp->u.str)
33: lp = ip->next;
34: }
35: putchar ('
');
36: }
37: }
38:
39: const char *search(const char *s)
40: {
39: unsigned int h = hash(s) % HASH_SIZE;
42: listnode_t * lp = hashTable[h];
43:
44: while (lp)
45: {
46: if (! strcmp (s, lp->u.str))
47: return lp->u.str;
48: lp = lp->next;
49: }
50: return NULL;
51: }
请参见:
3. 4 哪一种查找方法最方便?
3.5 哪一种查找方法最快?
3.8 怎样查找链表中的数据?
_____________________________________________
以下是一个简单示例:
#include<iostream>
#include<string>
using namespace std;
#define m 5 //人数
#define n 10 //哈希表长度
#define q 7 //随机数
struct name{
char *py;
int k;
};
name namelist[n];
struct hash{
char *py;
int k;
int s;
};
hash hashlist[n];
void listname()
{
char *f;
int s0,r,i;
namelist[0].py=as;
namelist[1].py=sa;
namelist[2].py=d;
namelist[3].py=f;
namelist[4].py=g;
for(i=0;i<m;i++)
{
s0=0;
f=namelist[i].py;
for(r=0;*(f+r)!='