基于字符串的Hash表效率实验分析
来源:互联网 发布:深圳龙岗ug编程培训 编辑:程序博客网 时间:2024/06/08 14:29
关键词:Hash表,Hash函数,冲突解决。
一、哈希表原理及运用
1、定义:散列表(Hash table),即哈希表,是根据关键字(Key value)而直接访问在内存存储位置的数据结构。也就是说,它是通过计算一个关于键值的函数,将所需查询的数据映射到表中的一个位置来访问记录,因此这可以加快查找速度。这个映射函数被称作散列函数,存放记录的数组被称作散列表。
2、思想:Hash算法的主要思想就是建立一种键-值(key-index)的储存数据的结构。我们只需要通过Hash函数将输入的待查找的值key转化成一个对应的整数,那么就可以将这个整数即键,作为一个简单的无序数组的索引,于是便可以快速的访问任意键的值。
3、运用:Hash主要用于信息安全领域中加密算法,它把一些不同长度的信息转化成杂乱的128位的编码,这些编码值叫做Hash值,从而达到加密的作用;日常生活中网络上常见歌曲电影等文件都有一个对应的Hash值,通过该值便可以做到快速访问的效果。
二、哈希函数的解析
在本次实验中,我一共用到了三种哈希函数,即BKDR、DJB和ELF,三种散列函数的实现方法如下:
BKDR散列函数
unsigned int BKDR_hash(string s) { unsigned int seed = 131; unsigned long hash = 0; int len = s.length(); for (int i = 0;i < len;i ++) hash = hash * seed + s[i]; return hash & 0x7FFFFFFF; }
DJB散列函数
unsigned DJB_hash(string s) { unsigned long hash = 5381; int len = s.length(); for (int i = 0;i < len;i ++) hash += (hash << 5) + s[i]; return hash & 0x7FFFFFFF;}
ELF散列函数
unsigned int ELF_hash(string s) { unsigned long hash = 0; int len = s.length(); for (int i = 0;i < len;i ++) { hash = (hash << 4) + s[i]; unsigned long g = hash & 0xf0000000L; if (g) hash ^= g >> 24; hash &= ~ g; } return hash;}
由于处理的对象为string类型,那么需要对string的每一位的字符进行运算处理,才可以得到一个相对唯一的hash值。三个函数看上去差别很大,但实际上也都是通过对每一位字符进行运算,然后进行取模和移位等操作,从而得到最终的Hash值。由于Hash值的范围会很大,所以在得到Hash值之后需要对Hash表的范围进行取模,确保该Hash值正好落在Hash表的范围内。
unsigned int,无符号的整型数据类型,在32位和64位的操作系统中都是占用4个字节,每个字节对应8位,所以一共对应32位,数值范围的上限应该减去1。1个16进制的F对应2进制数为1111,因此最多可以对应7个F。hash & 0x7FFFFFFF的意思也就是将hash的值与0x7FFFFFFF作取模运算。
三、冲突解决方法
在字符串通过Hash函数计算取模后,不同的字符串可能会得到相同的Hash值,这样的话多个字符串就会插入到同一个数组位置而造成数据的丢失和不完整。因此,为了避免这种冲突,我在实验中一共用了三种解决冲突的办法,即开放定址的线性探测法、二次探测法和拉链法。
1、开放定址法
开放定址法的基本思想就是将哈希表看成是一个循环的链式结构,即数组的头和尾链接起来。
在建立哈希表的时候,如果在插入数据的时候发生了冲突,那么就根据探测的方法向前逐个单元的查找,直到能够找到一个空位,然后将数据插入;在查找的时候,如果发现该位置的数据不对的时候,就根据相应的探测方法向前逐个单元的查找,直到找到正确的数据,如果查找到数据为空的情况,则说明查找失败,哈希表中没有这个数据。
(1)、线性探测法
线性探测法在构建哈希表的时候,特别要注意每次发生冲突后需要将下标加1之后在对哈希表的长度取模,形成一个循环的结构。代码如下:
void linear(int index,string eng,string chi) { while (1) { index ++; index %= test; if (dict[index].english == "") { dict[index].english = eng; dict[index].chinese = chi; dict[index].next = NULL; break; } else continue; }}
对于查找的时候,另外需要重新定义两个计数器,来记录在未能判断是查找成功还是查找失败的时候进行查找的次数。当查找结束后,将对应查找成功或者失败的计数器加到总的查找计数器上。代码如下:
string linear_judge(int index,string eng) { int su = 0; int in_su = 0; while (1) { index %= test; if (dict[index].english == "") { in_sum += in_su + 1; in_sumword ++; return "Not exist."; } else if (dict[index].english != eng) { su ++; in_su ++; index ++; index %= test; } else { sum += su + 1; sumword ++; return dict[index].chinese; } }}
(2)、二次探测法
二次探测法在构造哈希表的时候不同于线性的是每次下标加的是i的平方,而且i从1开始随着探测次数递增。代码如下:
void quadratic(int index,string eng,string chi) { int i = 1; while (1) { index += i*i; index %= test; if (dict[index].english == "") { dict[index].english = eng; dict[index].chinese = chi; dict[index].next = NULL; break; } else i ++; }}
对于查找的时候,与构造哈希表时改变相同的代码。代码如下:
string quadratic_judge(int index,string eng) { int su = 0; int in_su = 0; int i = 0; while (1) { index += i*i; index %= test; if (dict[index].english == "") { in_sum += in_su + 1; in_sumword ++; return "Not exist."; } else if (dict[index].english != eng) { su ++; in_su ++; i ++; continue; } else { sum += su + 1; sumword ++; return dict[index].chinese; } }}
2、拉链法
在我们写代码的时候,常用的数据结构有数组和链表。数组的特点是:寻址容易,插入和删除困难;而链表的特点是:寻址困难,插入和删除容易。那么结合数组和链表的优点,就得到了拉链法,结构模型如图:
原理就是当发生冲突的时候,不需要往下查找,而是将数组对应的该索引地址作为头结点,将发生冲突的数据往后插入,定义的数组为结构体数组,并且其中含有一个结构体指针,代码如下:
struct word { string english; string chinese; word *next; word(string eng = "",string chi = "",word *next = NULL) { english = eng; chinese = chi; this->next = next; }};
在使用拉链法构造哈希表的时候,注意可以直接将冲突的元素插在头结点的后面,把原本头结点后面的节点连接在冲突元素的后面。而不是通过遍历整个链表,最终插在链表的尾部,这样可以节省运行的时间。代码如下:
void chaining(int index,string eng,string chi) { word *p = new word(eng,chi) ; p->next = dict[index].next ; dict[index].next = p;}
但是在查找的时候,需要从头结点一直遍历到尾部,而且要特别注意记录查找成功和查找失败的计数器在代码中位置。
string chaining_judge(int index,string eng) { index %= test; if (dict[index].english == "") { in_sum += 1; in_sumword ++; return "Not exist."; } else if (dict[index].english == eng) { sum += 1; sumword ++; return dict[index].chinese; } else { word *p = dict[index].next; int su = 1; int in_su = 1; while (p != NULL) { su ++; in_su ++; if (p->english == eng) { sum += su; sumword ++; return p->chinese; } else p = p->next; } in_sum += in_su; in_sumword ++; return "Not exist."; }}
四、实验截图及数据与解决冲突算法分析
由于有三种hash函数,每种hash函数对应三种解决冲突的方法,每种方法又对应5个负载因子,运行截图共有3*3*5 = 45张。在这里只选取少量截图进行简单的说明。
使用BKDR函数进行线性探测法,查找单词失败平均次数为1.12次,花费时间为0.11s。
使用BKDR函数进行线性探测法,查找单词成功平均次数为1.06次,花费时间为0.11s。
使用DJB函数进行拉链法,查找单词成功的平均需要1.22次,花费的时间为0.34s。
使用ELF函数进行拉链法,查找单词失败的平均需要1.01次,花费的时间为 0.31s
运行所有情况之后,做出如下统计,括号外表示平均查找次数,括号中表示运行时间:
1、根据以上实验数据,我们可以很清楚的看到,并且得出以下结论(以下结论对于每个hash函数都是一样的,查找成功文件的数据和查找失败文件的数据得出的结论也是一样的):
(1)、当负载因子相同的时候,查找的效率是拉链法高于二次探测,并且二次探测高于线性探测。
(2)、无论是线性探测、二次探测还是拉链法,查找的效率均随着负载因子的增大而减小。特别是线性探测,减小的速率是越来越快。二次探测效率减小的速率相对较快,但拉链法减小的速率相对来说比较平和。
(3)、当负载因子很小的时候,大约为0.1以及小于0.1的时候,三种解决冲突的方法效率都比较接近。
(4)、原理同样都是开放定址法,二次探测法的效率在负载因子大于0.1后,远高于线性探测法。
(5)、很明显,拉链法的运行时间远高于线性探测法和二次探测法。
2、结论分析
(1)、负载因子的值是数据的个数与哈希表长度的比值,很显然,当哈希表的长度越大,即负载因子越小时,插入的记录之间产生冲突的几率就会越小。因此,查找的效率也会相对越高。
(2)、线性探测法很容易产生堆聚现象,堆聚现象就是存入哈希表的记录在表中连成一片。根据线性探测法处理冲突的原理来看,如果在哈希表中连续的序列越长,那么当新记录插入到表中的时候,就更容易与这个序列发生冲突,而且哈希地址较长的连续序列比较短的连续序列生长的速度更快,那么只要出现堆聚,就会引起进一步的堆聚。
(3)、二次探测法可以优化线性探测法带来的堆聚现象,它的思想是探测相隔较远的记录,而不是探测当前位置相邻的单元。只要发现有堆聚的现象,那么探测的位置变会越来越远。
(4)、拉链法处理冲突简单,而且不会存在堆聚现象,因此平均查找的次数比较少,而且拉链法会比较的节省空间。
(5)、由于拉链法每次发生冲突的时候,需要给新的节点开空间,在用new申请空间是很耗时间的,所以拉链法在运行的时候消耗的时间会相对比较多。
(6)、拉链法还有一个好处,不能从上述数据中得出,即删除数据的操作比较容易实现,只需要简单的完成一个链表节点的删除。而开放定址法是不能简单的删除数据的,因为一旦被删除的,该位置的数据将变为空,那么它将截断后面部分单词的查找路径。因为在查找过程中,一旦碰到数据为空是,即会认定查找失败。
3、分析补充
二次探测消除了在线性探测中产生的堆聚问题,这种问题叫做原始聚集。然后,二次探测产生了另外一种,更细的聚集问题。之所以会发生,是因为所有映射到同一个位置的关键字在寻找空位时,探测的单元都是一样的,因为其探测序列的步长总是固定的。
再哈希法:现在我们的需要的一种方法是产生一种依赖关键字的探测序列,而不是每个关键字都一样,那么不同的关键字即使映射到相同的数组下标,也可以使用不同的探测序列。方法就是把关键字用不同的哈希函数再做一次哈希化,用这个结果作为步长。为了满足这个条件,第二个哈希函数必须具备以下特点:
(1)、和第一个哈希函数不同。
(2)、不能输出0,否则将没有步长,那么算法将会陷入死循环。
五、哈希算法的效率
哈希表是在时间消耗和空间消耗上可以做出权衡一个算法。
1、如果没有内存的限制,那么可以直接将键值作为数组的索引,那么所有的查找时间的复杂度可以认为是O(1);
2、如果没有时间的限制,那么可以使用无序数组并且进行顺序查找,这样一来就只需要很少的内存。
因此,在实现哈希表的时候,我们可以通过调整哈希函数算法来在时间和空间上做出取舍。
六、实验过程中的困难及感想
1、文件流的操作是第一个困难,还是对流这个概念理解的不够。
(1)、ifstream表示读取文件,oftream表示输入到文件,二者的用法跟cin和cout差不多。
(2)、定义文件的时候,直接在对象名后括号里写上文件名,则表示文件已经打开,不是使用open函数。
(3)、判断文件是否读取完了,要用eof()函数来判断。
(4)、文件读取时,空格或者换行符将不同的数据之间间隔开,分次读取。
(5)、fstream既可以表示ifstream,也可以表示ofstream,但是如果是要生成一个文件并将数据输入的话,应该具体到ofstream,不然电脑也不知道怎么做。
2、getline函数的使用,该函数一共有三个参数,第一个参数为一个指针类型的字符数组,必须使用new关键字来开去新的空间,第二个参数为读取的字符的长度,第三个参数为停止读取的标识符。主要在本次实验中要给出足够的长度,期初给值50,但是发现有一个数据太大了,造成了错误,后来改为了100才正常。
3、在用拉链法构建哈希表的时候,当碰到冲突时插入数据,可以直接将节点插在头结点的后面,并将原先头结点之后的节点连接在刚插入的节点之后,这样一来可以将带代码简化到只有三行,而且也会减少很多的运行时间。
4、unsigned表示无符号的,在最开始写的时候,我没用上unsigned,结果运行时直接停止运行了,检查了好久也没找出来,后来我输出插入时的下标,发现了竟然有负数,这才加上了unsigned改正过来。unsigned int类型在32位和64位的操作系统中都是4个字节,每个字节占有八位,故一共有32位,取值范围的上限是2的32次方减1。
5、在查找的时候,使用hash函数后忘记了取模,导致了数组的越界,一开始怎么也看不出来,但是还要给的文件中第一个单词就越界了,所以后来还是查出了错误。以后一定要小心这种越界的错误。
部分代码
BKDR-Linear:线性探测法
#include <iostream>#include <fstream>#include <cstring>#include <string>#include <algorithm>#include <time.h>#include <iomanip>using namespace std;struct word { string english; string chinese; word *next; word(string eng = "",string chi = "",word *next = NULL) { english = eng; chinese = chi; this->next = next; }};const double length = 3209;const int test = 3241; //0.99//const int test = 3566; //0.9//const int test = 4011; //0.8//const int test = 6418; //0.5//const int test = 32090; //0.1word dict[test];double sum = 0; //查找成功的总次数 double in_sum = 0;double sumword = 0; //查找成功的单词个数 double in_sumword = 0;unsigned int BKDR_hash(string s) { unsigned int seed = 131; unsigned long hash = 0; int len = s.length(); for (int i = 0;i < len;i ++) hash = hash * seed + s[i]; return hash & 0x7FFFFFFF; }void linear(int index,string eng,string chi) { while (1) { index ++; index %= test; if (dict[index].english == "") { dict[index].english = eng; dict[index].chinese = chi; dict[index].next = NULL; break; } else continue; }}string linear_judge(int index,string eng) { int su = 0; int in_su = 0; while (1) { index %= test; if (dict[index].english == "") { in_sum += in_su + 1; in_sumword ++; return "Not exist."; } else if (dict[index].english != eng) { su ++; in_su ++; index ++; index %= test; } else { sum += su + 1; sumword ++; return dict[index].chinese; } }}void insert() { fstream table("dict.txt"); char *ch = new char[100]; string eng,chi; int index; while (!table.eof()) { table >> eng; table.getline(ch,100,'\n'); chi = ch; index = BKDR_hash(eng) % test; if (dict[index].english == "") { dict[index].english = eng; dict[index].chinese = chi; dict[index].next = NULL; } else linear(index,eng,chi); }}int main() { insert(); string eng,result; int index; double start,end; /* ifstream input("successful.txt"); ofstream output("BKDR_linear_su.txt"); start = clock(); while (!input.eof()) { input >> eng; index = BKDR_hash(eng); result = linear_judge(index,eng); output << eng << ": " << result << endl; } end = clock(); input.close(); output.close(); cout << "哈希函数: BKDR" << endl; cout << "查找方法: Linear" << endl; cout << "负载因子: " << fixed << setprecision(2) << length / test << endl; cout << "查找文件名: successful.txt" << endl; cout << "查找成功单词总数: " << sumword << endl; cout << "查找成功的总次数: " << sum << endl; cout << "查找成功的每个单词平均查找次数: " << fixed << setprecision(2) << sum / sumword << endl; cout << "查找失败的单词总数: " << in_sum << endl; cout << "查找失败的总次数: " << in_sumword << endl; if (in_sumword == 0) in_sumword = 1; cout << "查找失败的每个单词平均查找次数: " << fixed << setprecision(2) << in_sum / in_sumword << endl; cout << "查找并输出文件的运行时间: " << fixed << setprecision(2) << (end - start) / 1000 << " s" << endl; cout << "查找结果文件名: BKDR_linear_su.txt" << endl; */ ifstream input("unsuccessful.txt"); ofstream output("BKDR_linear_insu.txt"); start = clock(); while (!input.eof()) { input >> eng; index = BKDR_hash(eng); result = linear_judge(index,eng); output << eng << ": " << result << endl; } end = clock(); input.close(); output.close(); cout << "哈希函数: BKDR" << endl; cout << "查找方法: Linear" << endl; cout << "负载因子: " << fixed << setprecision(2) << length / test << endl; cout << "查找文件名: unsuccessful.txt" << endl; cout << "查找成功单词总数: " << sumword << endl; cout << "查找成功的总次数: " << sum << endl; if (sumword == 0) sumword = 1; cout << "查找成功的每个单词平均查找次数: " << fixed << setprecision(2) << sum / sumword << endl; cout << "查找失败的单词总数: " << in_sumword << endl; cout << "查找失败的总次数: " << in_sum << endl; if (in_sumword == 0) in_sumword = 1; cout << "查找失败的每个单词平均查找次数: " << fixed << setprecision(2) << in_sum / in_sumword << endl; cout << "查找并输出文件的运行时间: " << fixed << setprecision(2) << (end - start) / 1000 << " s" << endl; cout << "查找结果文件名: BKDR_linear_su.txt" << endl; return 0;}
BKDR-Quadratic:二次探测法
#include <iostream>#include <fstream>#include <cstring>#include <string>#include <algorithm>#include <time.h>#include <iomanip>using namespace std;struct word { string english; string chinese; word *next; word(string eng = "",string chi = "",word *next = NULL) { english = eng; chinese = chi; this->next = next; }};const double length = 3209;//const int test = 3241; //0.99//const int test = 3566; //0.9//const int test = 4011; //0.8//const int test = 6418; //0.5const int test = 32090; //0.1word dict[test];double sum = 0; //查找成功的总次数 double in_sum = 0;double sumword = 0; //查找成功的单词个数 double in_sumword = 0;unsigned int BKDR_hash(string s) { unsigned int seed = 131; unsigned long hash = 0; int len = s.length(); for (int i = 0;i < len;i ++) hash = hash * seed + s[i]; return hash & 0x7FFFFFFF; }void quadratic(int index,string eng,string chi) { int i = 1; while (1) { index += i*i; index %= test; if (dict[index].english == "") { dict[index].english = eng; dict[index].chinese = chi; dict[index].next = NULL; break; } else i ++; }}string quadratic_judge(int index,string eng) { int su = 0; int in_su = 0; int i = 0; while (1) { index += i*i; index %= test; if (dict[index].english == "") { in_sum += in_su + 1; in_sumword ++; return "Not exist."; } else if (dict[index].english != eng) { su ++; in_su ++; i ++; continue; } else { sum += su + 1; sumword ++; return dict[index].chinese; } }}void insert() { fstream table("dict.txt"); char *ch = new char[100]; string eng,chi; int index; while (!table.eof()) { table >> eng; table.getline(ch,100,'\n'); chi = ch; index = BKDR_hash(eng) % test; if (dict[index].english == "") { dict[index].english = eng; dict[index].chinese = chi; dict[index].next = NULL; } else quadratic(index,eng,chi); }}int main() { insert(); string eng,result; int index; double start,end; /* ifstream input("successful.txt"); ofstream output("BKDR_quadratic_su.txt"); start = clock(); while (!input.eof()) { input >> eng; index = BKDR_hash(eng); result = quadratic_judge(index,eng); output << eng << ": " << result << endl; } end = clock(); input.close(); output.close(); cout << "哈希函数: BKDR" << endl; cout << "查找方法: quadratic" << endl; cout << "负载因子: " << fixed << setprecision(2) << length / test << endl; cout << "查找文件名: successful.txt" << endl; cout << "查找成功单词总数: " << sumword << endl; cout << "查找成功的总次数: " << sum << endl; cout << "查找成功的每个单词平均查找次数: " << fixed << setprecision(2) << sum / sumword << endl; cout << "查找失败的单词总数: " << in_sum << endl; cout << "查找失败的总次数: " << in_sumword << endl; if (in_sumword == 0) in_sumword = 1; cout << "查找失败的每个单词平均查找次数: " << fixed << setprecision(2) << in_sum / in_sumword << endl; cout << "查找并输出文件的运行时间: " << fixed << setprecision(2) << (end - start) / 1000 << " s" << endl; cout << "查找结果文件名: BKDR_quadratic_su.txt" << endl; */ ifstream input("unsuccessful.txt"); ofstream output("BKDR_quadratic_insu.txt"); start = clock(); while (!input.eof()) { input >> eng; index = BKDR_hash(eng); result = quadratic_judge(index,eng); output << eng << ": " << result << endl; } end = clock(); input.close(); output.close(); cout << "哈希函数: BKDR" << endl; cout << "查找方法: quadratic" << endl; cout << "负载因子: " << fixed << setprecision(2) << length / test << endl; cout << "查找文件名: unsuccessful.txt" << endl; cout << "查找成功单词总数: " << sumword << endl; cout << "查找成功的总次数: " << sum << endl; if (sumword == 0) sumword = 1; cout << "查找成功的每个单词平均查找次数: " << fixed << setprecision(2) << sum / sumword << endl; cout << "查找失败的单词总数: " << in_sumword << endl; cout << "查找失败的总次数: " << in_sum << endl; if (in_sumword == 0) in_sumword = 1; cout << "查找失败的每个单词平均查找次数: " << fixed << setprecision(2) << in_sum / in_sumword << endl; cout << "查找并输出文件的运行时间: " << fixed << setprecision(2) << (end - start) / 1000 << " s" << endl; cout << "查找结果文件名: BKDR_quadratic_insu.txt" << endl; return 0;}
BDKR-Chaining:拉链法
#include <iostream>#include <fstream>#include <cstring>#include <string>#include <algorithm>#include <time.h>#include <iomanip>using namespace std;struct word { string english; string chinese; word *next; word(string eng = "",string chi = "",word *next = NULL) { english = eng; chinese = chi; this->next = next; }};const double length = 3209;//const int test = 3241; //0.99//const int test = 3566; //0.9//const int test = 4011; //0.8//const int test = 6418; //0.5const int test = 32090; //0.1word dict[test];double sum = 0; //查找成功的总次数 double in_sum = 0;double sumword = 0; //查找成功的单词个数 double in_sumword = 0;unsigned int BKDR_hash(string s) { unsigned int seed = 131; unsigned long hash = 0; int len = s.length(); for (int i = 0;i < len;i ++) hash = hash * seed + s[i]; return hash & 0x7FFFFFFF; }void chaining(int index,string eng,string chi) { word *p = new word(eng,chi) ; p->next = dict[index].next ; dict[index].next = p;}string chaining_judge(int index,string eng) { index %= test; if (dict[index].english == "") { in_sum += 1; in_sumword ++; return "Not exist."; } else if (dict[index].english == eng) { sum += 1; sumword ++; return dict[index].chinese; } else { word *p = dict[index].next; int su = 1; int in_su = 1; while (p != NULL) { su ++; in_su ++; if (p->english == eng) { sum += su; sumword ++; return p->chinese; } else p = p->next; } in_sum += in_su; in_sumword ++; return "Not exist."; }}void insert() { fstream table("dict.txt"); char *ch = new char[100]; string eng,chi; int index; while (!table.eof()) { table >> eng; table.getline(ch,100,'\n'); chi = ch; index = BKDR_hash(eng) % test; if (dict[index].english == "") { dict[index].english = eng; dict[index].chinese = chi; dict[index].next = NULL; } else chaining(index,eng,chi); }}int main() { insert(); string eng,result; int index; double start,end; /* ifstream input("successful.txt"); ofstream output("BKDR_chaining_su.txt"); start = clock(); while (!input.eof()) { input >> eng; index = BKDR_hash(eng); result = chaining_judge(index,eng); output << eng << ": " << result << endl; } end = clock(); input.close(); output.close(); cout << "哈希函数: BKDR" << endl; cout << "查找方法: chaining" << endl; cout << "负载因子: " << fixed << setprecision(2) << length / test << endl; cout << "查找文件名: successful.txt" << endl; cout << "查找成功单词总数: " << sumword << endl; cout << "查找成功的总次数: " << sum << endl; cout << "查找成功的每个单词平均查找次数: " << fixed << setprecision(2) << sum / sumword << endl; cout << "查找失败的单词总数: " << in_sumword << endl; cout << "查找失败的总次数: " << in_sum << endl; if (in_sumword == 0) in_sumword = 1; cout << "查找失败的每个单词平均查找次数: " << fixed << setprecision(2) << in_sum / in_sumword << endl; cout << "查找并输出文件的运行时间: " << fixed << setprecision(2) << (end - start) / 1000 << " s" << endl; cout << "查找结果文件名: BKDR_chaining_su.txt" << endl; */ ifstream input("unsuccessful.txt"); ofstream output("BKDR_chaining_insu.txt"); start = clock(); while (!input.eof()) { input >> eng; index = BKDR_hash(eng); result = chaining_judge(index,eng); output << eng << ": " << result << endl; } end = clock(); input.close(); output.close(); cout << "哈希函数: BKDR" << endl; cout << "查找方法: chaining" << endl; cout << "负载因子: " << fixed << setprecision(2) << length / test << endl; cout << "查找文件名: unsuccessful.txt" << endl; cout << "查找成功单词总数: " << sumword << endl; cout << "查找成功的总次数: " << sum << endl; if (sumword == 0) sumword = 1; cout << "查找成功的每个单词平均查找次数: " << fixed << setprecision(2) << sum / sumword << endl; cout << "查找失败的单词总数: " << in_sumword << endl; cout << "查找失败的总次数: " << in_sum << endl; if (in_sumword == 0) in_sumword = 1; cout << "查找失败的每个单词平均查找次数: " << fixed << setprecision(2) << in_sum / in_sumword << endl; cout << "查找并输出文件的运行时间: " << fixed << setprecision(2) << (end - start) / 1000 << " s" << endl; cout << "查找结果文件名: BKDR_chaining_insu.txt" << endl; return 0;}
- 基于字符串的Hash表效率实验分析
- 基于hash表的文件字符串替换
- 基于字符串的hash算法
- TrafficServer一致性Hash的实验分析
- 基于字符串的分离链接hash算法
- 基于字符串的分离链接hash算法
- 基于hash计算的多层实验流量切分的实现
- Hash表及hash算法的分析
- 基于C语言的hash表
- 字符串连接符效率分析
- 字符串数组初始化0 与memset 0 效率的分析
- 字符串数组初始化0 与memset 0 效率的分析
- 字符串数组初始化0 与memset 0 效率的分析
- 字符串数组初始化0 与memset 0 效率的分析
- 一个简单的字符串hash表
- 常见的字符串Hash
- 经典的字符串hash
- 字符串的Hash
- Git的最基本使用
- Linux添加系统调用
- 多线程学习总结(十)——线程安全之线程间的通信深入
- java json-lib & jQuery & jsonp
- 除法和算术右移之间的巧妙取代
- 基于字符串的Hash表效率实验分析
- JavaScript异步编程学习
- Mac apache和php
- 【Codeforces Round #200 (Div. 1)】Codeforces 343D Water Tree
- NOIP2015 day1[tarjan][搜索][模拟][贪心]
- jQuery图表(jqPlot,Highcharts)
- cmake 手册详解
- 上机1
- React.createClass( ) 和 React.Component( ) 有什么区别?