采用hash_map进行表格之间数据的查找

7 篇文章 0 订阅

背景:

本文尝试使用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[n]=*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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值