您的位置:首页 > 其它

采用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使用例子

代码:

#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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: