哈希表的综合应用(创建、处理冲突、查找成功和失败的次数)
2015-12-11 17:59
423 查看
最近学了数据结构中的哈希表,发现在计算等概率情况下查找不成功的平均查找长度时比较迷茫,不知道到底是怎么计算出来的。现在通过查阅资料终于知道如何计算了,所以记录下来以供以后查阅。
Question1:
将关键字序列(7、8、30、11、18、9、14)散列存储到散列表中。散列表的存储空间是一个下标从0开始的一维数组,散列函数为: H(key) = (keyx3) MOD 7,处理冲突采用线性探测再散列法,要求装填(载)因子为0.7。
(1) 请画出所构造的散列表。
(2) 分别计算等概率情况下查找成功和查找不成功的平均查找长度。
Ans:
(1).首先明确一个概念装载因子,装载因子是指所有关键子填充哈希表后饱和的程度,它等于 关键字总数/哈希表的长度。 根据题意,我们可以确定哈希表的长度为 L = 7/0.7 = 10;因此此题需要构建的哈希表是下标为0~9的一维数组。根据散列函数可以得到如下散列函数值表。
H(Key) = (keyx3) MOD 7, 例如key=7时, H(7) = (7x3)%7 = 21%7=0,其他关键字同理。
(表1)
采用线性探测再散列法处理冲突,所构造的散列表为:
(表2)
下面对散列表的构造方式加以说明,注意表1中的关键字7和14,30和9, 11和18,这三组关键子的H(Key)值相同,这在构建散列表时就会产生冲突,因为他们的地址相同,所以要通过一定的冲突处理方法来解决这个问题。依 题,采用线性探测再散列法处理冲突。下面详细介绍如何构建散列表:
第一个key 7,它的地址是0,因此放到散列表的数组下表为0的位置,这个位置上没有关键字,因此没有冲突可以直接填入;
第二个key 8,它的地址是3,因此放到散列表的数组下表为3的位置,这个位置上没有关键字,因此没有冲突可以直接填入;
第三个key 30,它的地址是6,因此放到散列表的数组下表为6的位置,这个位置上没有关键字,因此没有冲突可以直接填入;
第四个key 11,它的地址是5,因此放到散列表的数组下表为5的位置,这个位置上没有关键字,因此没有冲突可以直接填入;
第五个key 18,它的地址是5,因此放到散列表的数组下表为5的位置,但这个位置上已经有关键字11,遇到了冲突,此时我们根据线性探测再散列法来处理这个冲突,探 测下一个位置6, 6这个位置上已经存在关键字30则继续增加步长1,因此现在的新地址应为7,位置7上没有关键字,放入即可,到此冲突已经解决;
第六个key 9,它的地址是6,因此放到散列表的数组下表为6的位置,但这个位置上已经有关键字30,遇到了冲突,探测下一个位置7, 7这个位置上已经存在关键字18则继续增加步长1,因此现在的新地址应为8,位置8上没有关键字,放入即可;
第七个key 14,它的地址是0,因此放到散列表的数组下表为0的位置,但这个位置上已经有关键字7,遇到了冲突,探测下一个位置1, 位置1上没有关键字,放入即可;
到这一步所有关键字均已填入,散列表已经构造完成,如表2所示。
(2)等概率情况下查找成功平均查找长度:
这一问可以根据第一问的构造过程求解:
key7一次就填入了表中,因此查找次数为1,同理8, 30, 11查找次数均为1; key18 进行了3次放入操作,探测位置分别是5,6,7 ,因此查找次数为3;key9也是3次;key14 进行了两次探测,因此查找次数为2。次数表如表3所示
(表3)
所以ASLsuccess= (1+1+1+1+3+3+2)/ 7 = 12/7。
等概率情况下查找不成功的平均查找长度:
接下来讨论不成功的情况, 看表2,计算查找不成功的次数就直接找关键字到第一个地址上关键字为空的距离即可, 但根据哈希函数地址为MOD7,因此初始只可能在0~6的位置。等概率情况下,查找0~6位置查找失败的查找次数为:
看地址0,到第一个关键字为空的地址2的距离为3,因此查找不成功的次数为3.
地址1, 到第一个关键为空的地址2的距离为2,因此查找不成功的次数为2.
地址2, 到第一个关键为空的地址2的距离为1,因此查找不成功的次数为1.
地址3,到第一个关键为空的地址4的距离为2,因此查找不成功的次数为2.
地址4,到第一个关键为空的地址4的距离为1,因此查找不成功的次数为1.
地址5,到第一个关键为空的地址2(注意不是地址9,因为初始只可能在0~6之间,因此循环回去)的距离为5,因此查找不成功的次数为5.
地址6,到第一个关键为空的地址2(注意不是地址9,因为初始只可能在0~6之间,因此循环回去)的距离为4,因此查找不成功的次数为4.
因此查找不成功的次数表如下表所示
(表4)
所以ASLunsuccess= (3+2+1+2+1+5+4)/ 7 = 18/7。
下面是自己写的哈希表的代码(线性探测放置关键字和查找),包括哈希表的创建、发生冲突的次数,查找成功的次数和查找不成功的次数
Question1:
将关键字序列(7、8、30、11、18、9、14)散列存储到散列表中。散列表的存储空间是一个下标从0开始的一维数组,散列函数为: H(key) = (keyx3) MOD 7,处理冲突采用线性探测再散列法,要求装填(载)因子为0.7。
(1) 请画出所构造的散列表。
(2) 分别计算等概率情况下查找成功和查找不成功的平均查找长度。
Ans:
(1).首先明确一个概念装载因子,装载因子是指所有关键子填充哈希表后饱和的程度,它等于 关键字总数/哈希表的长度。 根据题意,我们可以确定哈希表的长度为 L = 7/0.7 = 10;因此此题需要构建的哈希表是下标为0~9的一维数组。根据散列函数可以得到如下散列函数值表。
H(Key) = (keyx3) MOD 7, 例如key=7时, H(7) = (7x3)%7 = 21%7=0,其他关键字同理。
Key | 7 | 8 | 30 | 11 | 18 | 9 | 14 |
H(Key) | 0 | 3 | 6 | 5 | 5 | 6 | 0 |
采用线性探测再散列法处理冲突,所构造的散列表为:
地址 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
关键字 | 7 | 14 | 8 | 11 | 30 | 18 | 9 |
下面对散列表的构造方式加以说明,注意表1中的关键字7和14,30和9, 11和18,这三组关键子的H(Key)值相同,这在构建散列表时就会产生冲突,因为他们的地址相同,所以要通过一定的冲突处理方法来解决这个问题。依 题,采用线性探测再散列法处理冲突。下面详细介绍如何构建散列表:
第一个key 7,它的地址是0,因此放到散列表的数组下表为0的位置,这个位置上没有关键字,因此没有冲突可以直接填入;
第二个key 8,它的地址是3,因此放到散列表的数组下表为3的位置,这个位置上没有关键字,因此没有冲突可以直接填入;
第三个key 30,它的地址是6,因此放到散列表的数组下表为6的位置,这个位置上没有关键字,因此没有冲突可以直接填入;
第四个key 11,它的地址是5,因此放到散列表的数组下表为5的位置,这个位置上没有关键字,因此没有冲突可以直接填入;
第五个key 18,它的地址是5,因此放到散列表的数组下表为5的位置,但这个位置上已经有关键字11,遇到了冲突,此时我们根据线性探测再散列法来处理这个冲突,探 测下一个位置6, 6这个位置上已经存在关键字30则继续增加步长1,因此现在的新地址应为7,位置7上没有关键字,放入即可,到此冲突已经解决;
第六个key 9,它的地址是6,因此放到散列表的数组下表为6的位置,但这个位置上已经有关键字30,遇到了冲突,探测下一个位置7, 7这个位置上已经存在关键字18则继续增加步长1,因此现在的新地址应为8,位置8上没有关键字,放入即可;
第七个key 14,它的地址是0,因此放到散列表的数组下表为0的位置,但这个位置上已经有关键字7,遇到了冲突,探测下一个位置1, 位置1上没有关键字,放入即可;
到这一步所有关键字均已填入,散列表已经构造完成,如表2所示。
(2)等概率情况下查找成功平均查找长度:
这一问可以根据第一问的构造过程求解:
key7一次就填入了表中,因此查找次数为1,同理8, 30, 11查找次数均为1; key18 进行了3次放入操作,探测位置分别是5,6,7 ,因此查找次数为3;key9也是3次;key14 进行了两次探测,因此查找次数为2。次数表如表3所示
Key | 7 | 8 | 30 | 11 | 18 | 9 | 14 |
Count | 1 | 1 | 1 | 1 | 3 | 3 | 2 |
所以ASLsuccess= (1+1+1+1+3+3+2)/ 7 = 12/7。
等概率情况下查找不成功的平均查找长度:
接下来讨论不成功的情况, 看表2,计算查找不成功的次数就直接找关键字到第一个地址上关键字为空的距离即可, 但根据哈希函数地址为MOD7,因此初始只可能在0~6的位置。等概率情况下,查找0~6位置查找失败的查找次数为:
看地址0,到第一个关键字为空的地址2的距离为3,因此查找不成功的次数为3.
地址1, 到第一个关键为空的地址2的距离为2,因此查找不成功的次数为2.
地址2, 到第一个关键为空的地址2的距离为1,因此查找不成功的次数为1.
地址3,到第一个关键为空的地址4的距离为2,因此查找不成功的次数为2.
地址4,到第一个关键为空的地址4的距离为1,因此查找不成功的次数为1.
地址5,到第一个关键为空的地址2(注意不是地址9,因为初始只可能在0~6之间,因此循环回去)的距离为5,因此查找不成功的次数为5.
地址6,到第一个关键为空的地址2(注意不是地址9,因为初始只可能在0~6之间,因此循环回去)的距离为4,因此查找不成功的次数为4.
因此查找不成功的次数表如下表所示
Key | 7 | 8 | 30 | 11 | 18 | 9 | 14 |
Count | 3 | 2 | 1 | 2 | 1 | 5 | 4 |
所以ASLunsuccess= (3+2+1+2+1+5+4)/ 7 = 18/7。
下面是自己写的哈希表的代码(线性探测放置关键字和查找),包括哈希表的创建、发生冲突的次数,查找成功的次数和查找不成功的次数
代码实现: #include <stdio.h> #include <stdlib.h> #define MAXSIZE 50 typedef int Typedata; typedef struct HashNode { Typedata *HT;//存放最终的关键字 Typedata *num;//存放输入的关键字 Typedata *broke;//冲突次数 Typedata *NUfod;//查找不成功的次数 Typedata key; }HashNode; Typedata i,k;//关键字的个数 void InitHash(HashNode &T)//初始化 { T.HT=(Typedata *)malloc(MAXSIZE*sizeof(Typedata)); T.num=(Typedata *)malloc(MAXSIZE*sizeof(Typedata)); T.broke=(Typedata *)malloc(MAXSIZE*sizeof(Typedata)); T.NUfod=(Typedata *)malloc(MAXSIZE*sizeof(Typedata)); for(i=0;i<MAXSIZE;i++) { T.HT[i]=0;T.num[i]=0;T.broke[i]=0; } } void CreateHash(HashNode T,Typedata k,Typedata m) { Typedata d,t; for(i=0;i<k;i++)//冲突的次数 { d=T.num[i]%m;t=1; while(T.HT[d]) { d=(d+1)%m; t++; } T.HT[d]=T.num[i]; T.broke[d]=t; } Typedata j,count; for(i=0;i<m;i++)//查找不成功的次数 { count=1; for(j=i;j<m;j++) { if(T.HT[j]!=0) count++; else break; if(T.HT[j]!=0&&j==m-1) j=-1; } T.NUfod[i]=count; } } void DisplayHash(HashNode T,Typedata m) { printf("\n哈希表的地址:"); for(i=0;i<m;i++) printf("%-4d",i); printf("\n表中的关键字:"); for(i=0;i<m;i++) printf("%-4d",T.HT[i]); printf("\n发生冲突次数:"); for(i=0;i<m;i++) printf("%-4d",T.broke[i]); printf("\n查找失败次数:"); for(i=0;i<m;i++) printf("%-4d",T.NUfod[i]); printf("\n"); } double EverageHash(HashNode T,Typedata m)//查找成功 { Typedata sum=0; double ave; for(i=0;i<m;i++) sum+=T.broke[i]; ave=(double)sum/k; return ave; } double NUEverageHash(HashNode T,Typedata m)//查找不成功 { Typedata sum2=0; double ave2; for(i=0;i<m;i++) sum2+=T.NUfod[i]; ave2=(double)sum2/m; return ave2; } int main() { HashNode T; char c='Y'; while(c=='Y') { InitHash(T);//初始化 Typedata m; printf("输入关键字的个数:"); scanf("%d",&k); printf("输入关键字\n"); for(i=0;i<k;i++) scanf("%d",&T.num[i]); printf("输入m="); scanf("%d",&m);//小于表的总长的最大素数 CreateHash(T,k,m);//创建 DisplayHash(T,m);//输出 printf("查找成功的平均查找长度ASL=%.2lf\n",EverageHash(T,m)); printf("查找不成功的平均查找长度NUASL=%.2lf\n",NUEverageHash(T,m)); printf("是否继续进行(Y/N) "); getchar();//接收回车 c=getchar(); printf("\n\n"); } return 0; } //测试用例 // 23 35 12 56 123 39 342 90 // m=11 // ASL=3.50 // NUASL=4.27 // 19 14 23 1 68 20 84 27 55 11 10 79 // m=13 // ASL=2.50 // NUASL=7.00测试用例的对应输出:
相关文章推荐
- 蓝桥杯——数列特征,字母图形 , 01字串 ,闰年判断
- 主备同步
- Hive 设置map 和 reduce 的个数
- OC如何读取本地文件和网络文件
- 手动编译Jsp文件
- 计算比例
- JS横向轮播
- python对象类型
- 23种设计模式
- 鼠标滚轮监测
- Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock'(2)
- 使用C++名单在文档处理和学生成绩管理系统相结合
- Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock'(2)
- 深入解析Java的Struts框架中的控制器DispatchAction
- python 写三级菜单
- IOS动画 (李梦珂)
- C++ primer札记10-继承
- Linux批量清理多个文件内容而不删除文件
- Pedro domingos
- 手把手教你如何安装和使用Karma-Jasmine