知识点:
知道什么是哈希查找,知道什么情况下产生冲突,知道产生冲突之后的解决方法有几种
选择题:
2-1散列冲突可以被描述为: (1分)
- 两个元素除了有不同键值,其它都相同
- 两个有不同数据的元素具有相同的键值
- 两个有不同键值的元素具有相同的散列地址
- 两个有相同键值的元素具有不同的散列地址
解析:冲突就是两个数据元素经过hash函数计算得到的hash值相同,也就是不同键值的元素具有相同的散列地址。
2-2将10个元素散列到100000个单元的哈希表中,是否一定产生冲突? (1分)
- 一定会
- 可能会
- 一定不会
- 有万分之一的可能会
解析:根据hash的原理我们知道可能会产生冲突。
2-3设散列表的地址区间为[0,16],散列函数为H(Key)=Key%17。采用线性探测法处理冲突,并将关键字序列{ 26,25,72,38,8,18,59 }依次存储到散列表中。元素59存放在散列表中的地址是: (2分)
- 8
- 9
- 10
- 11
解析:线性探测就是pos=(H(key)+i)%17,之要产生冲突i就从1开始取值,直到找到索引pos对应位置为空停止。
2-4采用线性探测法解决冲突时所产生的一系列后继散列地址: (1分)
- 必须大于等于原散列地址
- 必须小于等于原散列地址
- 可以大于或小于但不等于原散列地址
- 对地址在何处没有限制
解析:因为散列地址是为了将元素放置在数组里面,显然第三个是对的。
2-5将元素序列{18,23,11,20,2,7,27,33,42,15}按顺序插入一个初始为空的、大小为11的散列表中。散列函数为:H(Key)=Key%11,采用线性探测法处理冲突。问:当第一次发现有冲突时,散列表的装填因子大约是多少? (3分)
- 0.27
- 0.45
- 0.64
- 0.73
解析:装填因子就是列表当中已有的元素个数/列表的长度。
2-6给定散列表大小为11,散列函数为H(Key)=Key%11。按照线性探测冲突解决策略连续插入散列值相同的4个元素。问:此时该散列表的平均不成功查找次数是多少? (2分)
- 1
- 4/11
- 21/11
- 不确定
解析:因为连续插入4个相同的元素,并且查找不成功就是找到空位置就认定为元素不存在(因为采用的是线性探测),因此我们知道总次数N=5+4+3+2+7*1,因此平均就是21/11.
2-7从一个具有N个结点的单链表中查找其值等于X的结点时,在查找成功的情况下,需平均比较多少个结点? (2分)
- N/2
- N
- (N−1)/2
- (N+1)/2
解析:总次数是N*(N+1)/2,那么评均显然是第四个是正确的。
2-8若N个关键词被散列映射到同一个单元,并且用分离链接法解决冲突,则找到这N个关键词所用的比较次数为:(2分)
- N(N+1)/2
- N(N−1)/2
- N+1
- N
解析:这个时候就是单链表的元素查找计算。
2-9给定散列表大小为17,散列函数为H(Key)=Key%17。采用平方探测法处理冲突:hi(k)=(H(k)±i2)%17将关键字序列{ 6, 22, 7, 26, 9, 23 }依次插入到散列表中。那么元素23存放在散列表中的位置是:(3分)
- 0
- 2
- 6
- 15
解析:根据散列函数,以及平方探测的方法我们可以知道第二个是对的。
2-10给定散列表大小为17,散列函数为H(Key)=Key%17。采用平方探测法处理冲突:hi(k)=(H(k)±i2)%17将关键字序列{ 23, 22, 7, 26, 9, 6 }依次插入到散列表中。那么元素6存放在散列表中的位置是:(3分)
- 15
- 10
- 6
- 2
解析:跟上面哪一个没有任何区别,就是两个数不一样。
2-11将元素序列{18, 23, 4, 26, 31, 33, 17, 39}按顺序插入一个初始为空的、大小为13的散列表中。散列函数为:H(Key)=Key%13,采用线性探测法处理冲突。问:当第一次发现有冲突时,散列表的装填因子大约是多少? (3分)
- 0.54
- 0.63
- 0.31
- 0.62
解析:同之前的题目。
2-12给定散列表大小为11,散列函数为H(Key)=Key%11。按照线性探测冲突解决策略连续插入散列值相同的5个元素。问:此时该散列表的平均不成功查找次数是多少?(2分)
- 26/11
- 5/11
- 1
- 不确定
解析:同之前的题目。
函数题:
6-1 线性探测法的查找函数 (20分)
试实现线性探测法的查找函数。
函数接口定义:
Position Find( HashTable H, ElementType Key );
其中HashTable
是开放地址散列表,定义如下:
#define MAXTABLESIZE 100000 /* 允许开辟的最大散列表长度 */
typedef int ElementType; /* 关键词类型用整型 */
typedef int Index; /* 散列地址类型 */
typedef Index Position; /* 数据所在位置与散列地址是同一类型 */
/* 散列单元状态类型,分别对应:有合法元素、空单元、有已删除元素 */
typedef enum { Legitimate, Empty, Deleted } EntryType;
typedef struct HashEntry Cell; /* 散列表单元类型 */
struct HashEntry{
ElementType Data; /* 存放元素 */
EntryType Info; /* 单元状态 */
};
typedef struct TblNode *HashTable; /* 散列表类型 */
struct TblNode { /* 散列表结点定义 */
int TableSize; /* 表的最大长度 */
Cell *Cells; /* 存放散列单元数据的数组 */
};
函数Find
应根据裁判定义的散列函数Hash( Key, H->TableSize )
从散列表H
中查到Key
的位置并返回。如果Key
不存在,则返回线性探测法找到的第一个空单元的位置;若没有空单元,则返回ERROR
。
裁判测试程序样例:
#include <stdio.h>
#define MAXTABLESIZE 100000 /* 允许开辟的最大散列表长度 */
typedef int ElementType; /* 关键词类型用整型 */
typedef int Index; /* 散列地址类型 */
typedef Index Position; /* 数据所在位置与散列地址是同一类型 */
/* 散列单元状态类型,分别对应:有合法元素、空单元、有已删除元素 */
typedef enum { Legitimate, Empty, Deleted } EntryType;
typedef struct HashEntry Cell; /* 散列表单元类型 */
struct HashEntry{
ElementType Data; /* 存放元素 */
EntryType Info; /* 单元状态 */
};
typedef struct TblNode *HashTable; /* 散列表类型 */
struct TblNode { /* 散列表结点定义 */
int TableSize; /* 表的最大长度 */
Cell *Cells; /* 存放散列单元数据的数组 */
};
HashTable BuildTable(); /* 裁判实现,细节不表 */
Position Hash( ElementType Key, int TableSize )
{
return (Key % TableSize);
}
#define ERROR -1
Position Find( HashTable H, ElementType Key );
int main()
{
HashTable H;
ElementType Key;
Position P;
H = BuildTable();
scanf("%d", &Key);
P = Find(H, Key);
if (P==ERROR)
printf("ERROR: %d is not found and the table is full.\n", Key);
else if (H->Cells[P].Info == Legitimate)
printf("%d is at position %d.\n", Key, P);
else
printf("%d is not found. Position %d is returned.\n", Key, P);
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例1:(注:-1表示该位置为空。下同。)
11
11 88 21 -1 -1 5 16 7 6 38 10
38
输出样例1:
38 is at position 9.
输入样例2:
11
11 88 21 -1 -1 5 16 7 6 38 10
41
输出样例2:
41 is not found. Position 3 is returned.
输入样例3:
11
11 88 21 3 14 5 16 7 6 38 10
41
输出样例3:
ERROR: 41 is not found and the table is full.
AC代码:
Position Find(HashTable H, ElementType Key)
{
Position pos = Hash(Key, H->TableSize);
Position cur_pos = pos;
if(H->Cells[pos].Info == Legitimate && H->Cells[pos].Data == Key)
return pos;
int num_of_conflict = 0;
while(H->Cells[cur_pos].Info != Empty && H->Cells[cur_pos].Data != Key)
{
num_of_conflict++;
if(num_of_conflict == H->TableSize)
return ERROR;
cur_pos = (pos + num_of_conflict) % H->TableSize;
}
return cur_pos;
}