采用hash_map进行表格之间数据的查找
2015-09-26 15:00
288 查看
背景:
本文尝试使用hash_map进行数据之间的查找
方案分析:
1、hash_map基于hash table(哈希表)。哈希表最大的优点,就是把数据的插入和查找消耗的时间大大降低,几乎可以看成是常数时间;而代价仅仅是消耗比较多的内存。然而在当前可利用内存越来越多的情况下,用空间换时间的做法是值得的。另外,编码比较容易也是它的特点之一。
1)其基本原理是:
使用一个下标范围比较大的数组来存储元素。通过设计一个函数(哈希函数,也叫做散列函数),使得每个元素的关键字都与一个函数值(即数组下标,hash值)相对应,由于这重映射关系,于是用这个数组单元来存储这个元素;也可以简单的理解为,按照关键字为每一个元素“分类”,然后将这个元素存储在相应“类”所对应的地方,称为桶。
但是,不能够保证每个元素的关键字与函数值是一一对应的,因此极有可能出现对于不同的元素,却计算出了相同的函数值,这样就产生了“冲突”,换句话说,就是把不同的元素分在了相同的“类”之中。总的来说,“直接定址”与“解决冲突”是哈希表的两大特点。
2)hash_map,首先分配一大片内存,形成许多桶。再利用hash函数,对key进行映射到不同区域(桶)进行保存。
其插入过程是:
(1)得到key
(2)通过hash函数得到hash值
(3)得到桶号(一般都为hash值对桶数求模)
(4)存放key和value在桶内。
其取值过程(查找)是:
(1)得到key
(2)通过hash函数得到hash值
(3)得到桶号(一般都为hash值对桶数求模)
(4)比较桶的内部元素是否与key相等,若都不相等,则没有找到。
(5)取出相等的记录的value。
hash_map中直接地址用hash函数生成,解决冲突,用比较函数解决。这里可以看出,如果每个桶内部只有一个元素,那么查找的时候只有一次比较。当许多桶内没有值时,许多查询就会更快了(指查不到的时候)。由此可见,要实现哈希表, 和用户相关的是:hash函数和比较函数。这两个参数刚好是我们在使用hash_map时需要指定的参数。
3)hash _map使用例子
代码:
2、讨论:
1)、其实在hash_map自带默认的hash函数,可以直接用,而不用自行设计,也不必使用std::tr1::hash来独立进行映射。
2)、每行读取的数据,其实也没有必要存放于map之中,因为map是有序的,每增加一个数据,都需要维持其有序性,增加了额外的操作。按照本文的需求,其实verctor就可以
3)、本文中的std::map<std::string,char> krc_keyvalue1,其实是此前采用map进行两个表格数据的查找,记住方法1,而本文这里的hash_map暂记为方法2。该方法在查找上的关键代码如下:
参考过的资料:
http://www.it165.net/pro/html/201504/39277.html http://www.2cto.com/kf/201304/199523.html http://www.waitingfy.com/archives/480 http://f.dataguru.cn/thread-370937-1-1.html
本文尝试使用hash_map进行数据之间的查找
方案分析:
1、hash_map基于hash table(哈希表)。哈希表最大的优点,就是把数据的插入和查找消耗的时间大大降低,几乎可以看成是常数时间;而代价仅仅是消耗比较多的内存。然而在当前可利用内存越来越多的情况下,用空间换时间的做法是值得的。另外,编码比较容易也是它的特点之一。
1)其基本原理是:
使用一个下标范围比较大的数组来存储元素。通过设计一个函数(哈希函数,也叫做散列函数),使得每个元素的关键字都与一个函数值(即数组下标,hash值)相对应,由于这重映射关系,于是用这个数组单元来存储这个元素;也可以简单的理解为,按照关键字为每一个元素“分类”,然后将这个元素存储在相应“类”所对应的地方,称为桶。
但是,不能够保证每个元素的关键字与函数值是一一对应的,因此极有可能出现对于不同的元素,却计算出了相同的函数值,这样就产生了“冲突”,换句话说,就是把不同的元素分在了相同的“类”之中。总的来说,“直接定址”与“解决冲突”是哈希表的两大特点。
2)hash_map,首先分配一大片内存,形成许多桶。再利用hash函数,对key进行映射到不同区域(桶)进行保存。
其插入过程是:
(1)得到key
(2)通过hash函数得到hash值
(3)得到桶号(一般都为hash值对桶数求模)
(4)存放key和value在桶内。
其取值过程(查找)是:
(1)得到key
(2)通过hash函数得到hash值
(3)得到桶号(一般都为hash值对桶数求模)
(4)比较桶的内部元素是否与key相等,若都不相等,则没有找到。
(5)取出相等的记录的value。
hash_map中直接地址用hash函数生成,解决冲突,用比较函数解决。这里可以看出,如果每个桶内部只有一个元素,那么查找的时候只有一次比较。当许多桶内没有值时,许多查询就会更快了(指查不到的时候)。由此可见,要实现哈希表, 和用户相关的是:hash函数和比较函数。这两个参数刚好是我们在使用hash_map时需要指定的参数。
3)hash _map使用例子
代码:
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string> #include <tr1/functional> #include <time.h> #include <map> #include <vector> #include <queue> #include <hashtable.h> #include <hash_map> #include <ext/hash_map> #include <algorithm> #include <fstream> #include <sstream> #include<cstring> #include <time.h> //字符串分割函数 std::vector<std::string> split( std::string str, std::string pattern) { std::vector<std::string> ret; if(pattern.empty()) return ret; size_t start=0,index=str.find_first_of(pattern,0); while(index!=str.npos) { if(start!=index) ret.push_back(str.substr(start,index-start)); start=index+1; index=str.find_first_of(pattern,start); } if(!str.substr(start).empty()) ret.push_back(str.substr(start)); return ret; } //字符分隔函数2:字符串分割函数.默认采用空格和"-"作为分隔符, std::vector<std::string> splitV2( std::string str) { std::vector<std::string> ret; const char *d = " -";//分隔符 char *p; char *c = strdup(str.c_str());//因为c_str是const char*类型,而strtok要求输入为char*型,所以需求先转型 p = strtok(c,d); while(p) { printf("%s\n",p); ret.push_back(p); p=strtok(NULL,d); } return ret; } int main() { std::cout<<"Run the match---"<<std::endl; time_t start = clock(); std::ifstream file0( "//home//liujiepeng//liutest//9_9-1.csv" ); // declare file stream: std::ifstream file1( "//home//liujiepeng//liutest//9_11-1.csv" ); // declare file stream: std::string strtemp; std::map<std::string,char> krc_keyvalue0; std::queue<std::string> tempqueue; getline(file0,strtemp); tempqueue.push(strtemp); //读取9_9-1.csv while(getline(file0,strtemp)) { tempqueue.push(strtemp); std::vector< std::string> result=split(strtemp,","); std::vector<std::string>::iterator veciter = result.begin(); veciter++; //std::cout<<*veciter<<" "; krc_keyvalue0.insert(std::pair<std::string,char>(*veciter,'N')); veciter++; //std::cout<<*veciter<<std::endl; } //读取11的内容 std::map<std::string,char> krc_keyvalue1; getline(file1,strtemp); std::tr1::hash<std::string> h; size_t n; //采用hash_map __gnu_cxx::hash_map<int,std::string> myhashmap;//hash_map并没有排序好 __gnu_cxx::hash_map<int,std::string>::iterator hashmapiter; int TabNum = 0; while(getline(file1,strtemp)) { std::vector< std::string> result1=split(strtemp,","); std::vector<std::string>::iterator veciter1 = result1.begin(); veciter1++; std::cout<<*veciter1<<std::endl; // 将11号表格的关键字进行分词,再进行插入到map之中 //在此注意分词,将非文字包括空格和"-"均视为分隔符.不能仅仅将空格作为分隔符,英文歌曲名会尴尬 std::vector< std::string> result1_1=split(*veciter1," - ");//仅仅考虑了"-"作为分隔符 std::vector<std::string>::iterator veciter1_1;// = result1_1.begin(); //将所有的分词结果写到map之中 for(veciter1_1 = result1_1.begin();veciter1_1 != result1_1.end(); veciter1_1++) { krc_keyvalue1.insert(std::pair<std::string,char>(*veciter1_1,'N')); n = h(*veciter1_1);//将字库进行hash myhashmap =*veciter1_1;//将词库放置到hash表格中 } } //在11号表格完成分词之后,对该词库进行hash //进行两个表的match 操作,在这里可以根据不同的数据结构选择不同的方法 std::map<std::string,char>::iterator iter0; std::map<std::string,char>::iterator iter1; int method=0; for(iter0=krc_keyvalue0.begin();iter0 != krc_keyvalue0.end(); iter0++) { iter1=krc_keyvalue1.end(); // iter1_1=krc_keyvalue1.end(); //std::cout<<iter0->first<<std::endl;//难道是因为insert的时候顺序是随意的??并不是,是因为map的所有元素会根据key值自动排序 //先对iter0-first进行分词 std::vector< std::string> result0_1=split(iter0->first," - ");//仅仅考虑了"-"作为分隔符 std::vector<std::string>::iterator veciter0_1;//一般默认分词结果只有两分部,这也是一般的情况 for(veciter0_1 = result0_1.begin();veciter0_1 != result0_1.end(); veciter0_1++) { hashmapiter=myhashmap.find(h(*veciter0_1));// if(hashmapiter != myhashmap.end()) { iter0->second = 'Y'; break; } } } //写到 std::ofstream streamfile_0("//home//liujiepeng//liutest//9_9_new.csv"); std::ofstream streamfile_1("//home//liujiepeng//liutest//9_11_new.csv"); std::string new_str; new_str = tempqueue.front(); streamfile_0<<new_str<<std::endl; tempqueue.pop(); std::map<std::string,char>::iterator iternew; while(!tempqueue.empty()) { new_str = tempqueue.front(); std::vector< std::string> resultnew1=split(new_str,","); std::vector<std::string>::iterator veciternew1 = resultnew1.begin(); veciternew1++;//关键字位于第二列,第三列是点击数,第四列为待修改的,置为N或者Y //std::cout<<*veciternew1<<std::endl; iternew = krc_keyvalue0.find(*veciternew1);//查找map中对应的位置 //std::cout<<iternew->second<<std::endl;//读取该字符是N还是Y //在确定该歌曲所对应的是N还是Y之后 //定位第二个,因为第二个,之后的字符串是等待替换的 std::string::iterator iter_frond,iter_back,iter_temp; int i = 0; for( iter_temp = new_str.begin(); iter_temp < new_str.end(); iter_temp++ ) { if(*iter_temp == ',') i++; if(i == 3)//第三个逗号 { iter_frond = ++iter_temp; i++; continue; } if(i-1 == 4)//第四个逗号 { iter_back = iter_temp; break; } } i=0; //const char* theword="Y"; if(iternew->second == 'Y') { new_str.replace(iter_frond,iter_back,"Y");//对该行进行操作,替换成Y或者是. //std::cout<<new_str.c_str()<<std::endl; } else if(iternew->second == 'N') { new_str.replace(iter_frond,iter_back,"N");//替换成N或者否.另外一种方法是对resultnew1进行操作 } streamfile_0<<new_str<<std::endl; tempqueue.pop(); } time_t end = clock(); std::cout<<"TotalTime:"<<end-start<<"ms"<<std::endl; return 0; }
2、讨论:
1)、其实在hash_map自带默认的hash函数,可以直接用,而不用自行设计,也不必使用std::tr1::hash来独立进行映射。
2)、每行读取的数据,其实也没有必要存放于map之中,因为map是有序的,每增加一个数据,都需要维持其有序性,增加了额外的操作。按照本文的需求,其实verctor就可以
3)、本文中的std::map<std::string,char> krc_keyvalue1,其实是此前采用map进行两个表格数据的查找,记住方法1,而本文这里的hash_map暂记为方法2。该方法在查找上的关键代码如下:
std::map<std::string,char>::iterator iter1=krc_keyvalue1.find(*veciter0_1);//进行查找 iter1_1=krc_keyvalue1.find(*veciter0_1); if (iter1 != krc_keyvalue1.end()) { iter0->second = 'Y';//printf("not found\n");//krc_keyvalue0// break; }
参考过的资料:
http://www.it165.net/pro/html/201504/39277.html http://www.2cto.com/kf/201304/199523.html http://www.waitingfy.com/archives/480 http://f.dataguru.cn/thread-370937-1-1.html
相关文章推荐
- html5定位
- 项目实操Mono+Linux配置 实现ASP.NET运行
- vmtools安装完后为什么无法粘贴
- Emmet语法
- 设备访问机制------阻塞与非阻塞
- SQL Server分页存储过程的五种方法及性能比较
- 数制知识小结
- Android杂谈-RelativeLayout中的baseline是什么
- Android Provider获取通信录
- 微软称今后所有的Win10发行包都是累积的
- iOS基础-事件处理、响应者链
- 2015 ACM/ICPC Asia Regional Shanghai Online A Sweet Journey(简单题)
- 记录——《C Primer Plus (第五版)》第七章编程练习第八题
- android 解析XML方式(三)
- Hive 笔记之 加载数据时,找不到文件路径异常
- SQL中的case when then else end用法
- android MSM8974 上DeviceTree简介
- android 解析XML方式(二)
- android MSM8974 上DeviceTree简介
- 论自动化测试是否可以完全取代手工测试?