STL之hash_map

来源:互联网 发布:中国8个一线城市 知乎 编辑:程序博客网 时间:2024/05/29 14:23

hash_map简介(下列在VS2010下测试)

hash_map的用法和map是一样的,提供了insert,size,count等操作,并且里面的元素也是以pair类型来存贮的。虽然对外部提供的函数和数据类型是一致的,但是其底层实现是完全不同的,map底层的数据结构是rb_tree而,hansh_map却是哈希表来实现的。

总体来说,hash_map 查找速度会比map快,而且查找速度基本和数据量大小无关,属于常数级别;而map的查找速度是log(n)级别。hash还有hash函数的耗时。当有100w条记录的时候,map也只需要20次的比较,200w也只需要21次的比较!所以并不一定常数就比log(n)

hash_map对空间的要求要比map高很多,所以是以空间换时间的方法,而且,对应hash_map,如果hash函数和hash因子选择不好的话,也许不会达到你要的效果,所以至于用map,还是hash_map,从3个方面来权衡:查找速度,数据量,内存使用,还有一个就是你的经验!没有特别的标准。

hash_map类在头文件hash_map中,和所有其它的C++标准库一样,头文件没有扩展名。如下声明:

#include <hash_map>

using namespace std;

using namespace stdext;

 

hash_map是一个聚合类,它继承自_Hash类,包括一个vector,一个list和一个pair,其中vector用于保存桶,list用于进行冲突处理,pair用于保存key->value结构,简要地伪码如下:

class hash_map<class _Tkey, class _Tval>

{

private:

    typedef pair<_Tkey, _Tval> hash_pair;

     typedef list<hash_pair>    hash_list;

    typedef vector<hash_list> hash_table;

};

另外可以通过重写 hash_compair仿函数,更改里面关于桶数量的定义,如果取值合适,也可以得到更优的性能。而且如果你的数据是自定义的类型,必须要重写这个仿函数。可以模仿原来的写法,所有的成员函数,成员变量一个不能少!

简单的一个列子,其使用方法和map是一样的:

#include <iostream>#include <hash_map>#include <string>using namespace std; int main(){         hash_map<int,string>hmap;//定义一个实例         hmap.insert(pair<int,string>(10,"hashMap"));//插入一个pair对象         hmap.insert(hash_map<int,string>::value_type(34,"test"));//value_type就是pair类型的          hmap[23] = "23";         hmap[33] = "33";         hmap[-1] = "-1";         cout<<"begin-->end:"<<endl;         hash_map<int,string>::iteratorit = hmap.begin();         while(it!=hmap.end())//遍历         {                   cout<<it->first<<"\t"<<it->second<<endl;                   it++;         }          cout<<"find:"<<endl;         it = hmap.find(-1);// 查找         if(it!=hmap.end())         {                   cout<<it->first<<"\t"<<it->second<<endl;                   it++;         }          cout<<"size:"<<endl;         cout<<hmap.size()<<endl;         cout<<"count:"<<endl;         cout<<hmap.count(58)<<endl;         cout<<"empty:"<<endl;         cout<<hmap.empty()<<endl;          system("pause");         return 0;}



简单变量作为索引:整形、实性、指针型:

#include <iostream>#include <hash_map>using namespace std; /*写一个仿函数CharLess,继承自仿函数基类binary_function *当然也可以不继承,这样写只是符合标准,而且写起来比较方便,不用被类似于指针的指针和指针的引用搞晕*/struct CharLess : publicbinary_function<const char*, const char*,bool>{public:         result_type operator()(const first_argument_type& _Left,const second_argument_type& _Right)const         {                   return(stricmp(_Left,_Right) < 0 ?true :false);         }}; int main(){         hash_map<constchar*,int,hash_compare<constchar*,CharLess>> CharHash;                 CharHash["b"]= 456;         CharHash["a"]= 123;         charszInput[64] = "c";         CharHash[szInput] = 564;          hash_map<constchar*,int,hash_compare<constchar*,CharLess>>::iterator iter=CharHash.begin();         while(iter!=CharHash.end())         {                   cout<<iter->first<<" "<<iter->second<<endl;                   iter++;         }          system("pause");         return 0;}



用户自定义类型:比如对象类型,结构体:

#include <iostream>#include <hash_map>#include <string>using namespace std; struct string_less : publicbinary_function<const string, const string, bool>{public:         result_type operator()(const first_argument_type& _Left,const second_argument_type& _Right)const         {                   return(_Left.compare(_Right)< 0 ?true :false);         }}; int main(){         hash_map<string, int, hash_compare<string, string_less>>StringHash;         StringHash["a"]= 123;         StringHash["b"]= 456;          string strKey = "c";         StringHash[strKey];          hash_map<string, int, hash_compare<string,string_less>>::iterator iter=StringHash.begin();         while(iter!=StringHash.end())         {                   cout<<iter->first<<" "<<iter->second<<endl;                   iter++;         }          system("pause");         return 0;}



PS:

如何用hash_map替换程序中已有的map容器?

这个很容易,但需要你有良好的编程风格。建议你尽量使用typedef来定义你的类型:

typedef map<Key,Value> KeyMap;

当你希望使用hash_map来替换的时候,只需要修改:

typedefhash_map<Key, Value> KeyMap;

其他的基本不变。当然,你需要注意是否有Key类型的hash函数和比较函数。

 

常用的字符串类CString类型:

#include <hash_map>#include <atlstr.h>//CString头文件#include <iostream> using namespace std;inline size_t CString_hash_value(const CString& str){         size_t value = _HASH_SEED;         size_t size  = str.GetLength();         if(size > 0) {                   size_t temp = (size / 16) +1;                   size -= temp;                   for(size_t idx = 0; idx <= size; idx += temp) {                            value +=(size_t)str[(int)idx];                  }         }         return(value);} class CString_hash_compare : publichash_compare<CString>{public:         size_t operator()(const CString& _Key)const         {                   return((size_t)CString_hash_value(_Key));         }          bool operator()(constCString& _Keyval1, const CString& _Keyval2)const         {                   return(comp(_Keyval1, _Keyval2));         }}; int main(){         hash_map<CString, int, CString_hash_compare> CStringHash;         CStringHash["12"]= 12;         CStringHash["13"]= 13;         hash_map<CString, int, CString_hash_compare>::iterator iter=CStringHash.begin();         while(iter!=CStringHash.end())         {                   cout<<iter->first<<" "<<iter->second<<endl;//CString :cout在Unicode模式下不显示字符串                   iter++;         }          system("pause");         return 0;}



自定义对象的使用方法:

#include <hash_map>#include <atlstr.h>//CString头文件#include <iostream>using namespace std; //接口中规定了比较运算符,所以这里可以使用标准的less仿函数,所以这里忽略template<class_Tkey>  class MyHashCompare : publichash_compare<_Tkey> {  public:/*      enum           {  //   parameters   for  hash   table                     bucket_size   =  4,   //   0  <   bucket_size                     min_buckets   =  8  //   min_buckets  =   2   ^^  N,   0   <  N           };*/         size_t operator()(const _Tkey& _Key)const{                     return(_Key.hash_value());           }           bool operator()(const_Tkey& _Keyval1, const _Tkey& _Keyval2)const {                     return(comp(_Keyval1, _Keyval2));           }  }; struct IHashable //接口{         virtualunsignedlonghash_value()const = 0;         virtualbooloperator< (const IHashable& val)const = 0;         virtualIHashable& operator = (const IHashable& val) = 0;}; class CTest : publicIHashable{public:         intm_value;         CString m_message;public:         CTest() : m_value(0) {}          CTest(constCTest& obj)         {                   m_value = obj.m_value;                   m_message = obj.m_message;         } public:         virtualIHashable& operator = (const IHashable& val) {                   m_value   = ((CTest&)val).m_value;                   m_message = ((CTest&)val).m_message;                   return(*this);         }          virtualunsignedlonghash_value()const {                   //这里使用类中的m_value域计算hash值,也可以使用更复杂的函数计算所有域总的hash值                   return(m_value^0xdeadbeef);         }          virtualbooloperator< (const IHashable& val)const {                   return(m_value< ((CTest&)val).m_value);         }}; int main(){         CTest test;           test.m_value = 123;           test.m_message = "This is a test";           hash_map<CTest,int,MyHashCompare<CTest>> MyHash;         MyHash[test] = 2010;          hash_map<CTest,int,MyHashCompare<CTest>>::iteratoriter=MyHash.begin();         while(iter!=MyHash.end())         {                   wcout<<(iter->first).m_value<<(LPCTSTR)((iter->first).m_message);// LPCTSTR转换                   wcout<<" "<<iter->second<<endl;                   //cout<<MyHash[test]<<endl;                   iter++;         }          system("pause");         return 0;}


 

如何在hash_map中加入自己定义的类型:要做两件事,定义hash函数,定义等于比较函数。

#include <hash_map>#include <string>#include <iostream> using namespace std;class ClassA{public:         ClassA(inta):c_a(a){}         intgetvalue()const {returnc_a;}         voidsetvalue(int a){c_a;}private:         intc_a;}; struct hash_A{         enum            {  //  parameters   for   hash  table                     bucket_size   =  4,   //   0  <   bucket_size                     min_buckets   =  8  //   min_buckets  =   2   ^^  N,   0   <  N           };          //1 definethe hash function         size_t operator()(constclass ClassA& A)const{                   //   return hash<int>(A.getvalue());                   returnA.getvalue();         }          //2 definethe equal function         bool operator()(const class ClassA & a1, constclass ClassA & a2)const{                   return  a1.getvalue() < a2.getvalue();         }}; int main(){         hash_map<ClassA, string, hash_A>hmap;          ClassA a1(12);         hmap[a1]="Iam 12";         ClassA a2(198877);         hmap[a2]="Iam 198877";          cout<<hmap[a1]<<endl;         cout<<hmap[a2]<<endl;          system("pause");         return 0;}



//use a map to create a phone directory#include <iostream>#include <map>#include <cstring>using namespace std; class name{private:         charstr[40];public:         name() {strcpy(str,"");}         name(char*s) {strcpy(str,s);}         char*get() {return str;}}; //mustdefine less than relative to name objectsbool operator<(namea,name b){         returnstrcmp(a.get(),b.get()) < 0;} class phoneNum{private:         charstr[80];public:         phoneNum(){strcpy(str,"");}         phoneNum(char*s){strcpy(str,s);}         char*get(){return str;}}; int main(){         map<name,phoneNum> directory;          //put namesand numbers into map         directory.insert(pair<name,phoneNum>(name("Tom"),phoneNum("555-4533")));         directory.insert(pair<name,phoneNum>(name("Chris"),phoneNum("555-9678")));         directory.insert(pair<name,phoneNum>(name("John"),phoneNum("555-8195")));         directory.insert(pair<name,phoneNum>(name("Rachel"),phoneNum("555-0809")));          //given aname,find number         charstr[80];         cout << "entername: ";         cin >> str;          map<name,phoneNum>::iterator p;         p = directory.find(name(str));          if(p !=directory.end())                   cout << "phone number: " <<p->second.get()<<endl;         else                   cout << "name not in directory"<<endl;          system("pause");         return 0;}


 

 

 

0 0
原创粉丝点击