码迷,mamicode.com
首页 > 编程语言 > 详细

hash_map原理及C++实现

时间:2015-06-23 11:59:53      阅读:166      评论:0      收藏:0      [点我收藏+]

标签:

一、数据结构:hash_map原理 
hash_map基于hash table(哈希表)。哈希表最大的优点,就是把数据的存储和查找消耗的时间大大降低,几乎可以看成是常数时间;而代价仅仅是消耗比较多的内存。然而在当前可利用内存越来越多的情况下,用空间换时间的做法是值得的。另外,编码比较容易也是它的特点之一。 

其基本原理是:使用一个下标范围比较大的数组来存储元素。可以设计一个函数(哈希函数,也叫做散列函数),使得每个元素的关键字都与一个函数值(即数组下标,hash值)相对应,于是用这个数组单元来存储这个元素;也可以简单的理解为,按照关键字为每一个元素“分类”,然后将这个元素存储在相应“类”所对应的地方,称为桶。 

但是,不能够保证每个元素的关键字与函数值是一一对应的,因此极有可能出现对于不同的元素,却计算出了相同的函数值,这样就产生了“冲突”,换句话说,就是把不同的元素分在了相同的“类”之中。 总的来说,“直接定址”与“解决冲突”是哈希表的两大特点。 

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函数(hashcode)和比较函数(equals)。

假定哈希函数将元素正确分布在各桶之间,可为基本操作(get 和 put)提供稳定的性能。迭代集合视图所需的时间与 HashMap 实例的“容量”(桶的数量)及其大小(键-值映射关系数)的和成比例。所以,如果迭代性能很重要,则不要将初始容量设置得太高(或将加载因子设置得太低)。 HashMap 的实例有两个参数影响其性能:初始容量 加载因子容量 是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,通过调用 rehash 方法将容量翻倍。 通常,默认加载因子 (.75) 在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数 HashMap 类的操作中,包括 get 和 put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地降低 rehash 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 rehash 操作。 如果很多映射关系要存储在 HashMap 实例中,则相对于按需执行自动的 rehash 操作以增大表的容量来说,使用足够大的初始容量创建它将使得映射关系能更有效地存储。 注意,此实现不是同步的。如果多个线程同时访问此映射,而其中至少一个线程从结构上修改了该映射,则它必须 保持外部同步。(结构上的修改是指添加或删除一个或多个映射关系的操作;仅改变与实例已经包含的键关联的值不是结构上的修改。)这一般通过对自然封装该映射的对象进行同步操作来完成。如果不存在这样的对象,则应该使用 Collections.synchronizedMap 方法来“包装”该映射。最好在创建时完成这一操作,以防止对映射进行意外的不同步访问,如下所示: Map m = Collections.synchronizedMap(new HashMap(...)); 
技术分享
今天在使用STL中的hash_map模板遇到使用PTCHAR作为Key时无法对字符串进行正确比较的问题,在网上查找相应的文章可惜没有找到,但找到了http://www.stlchina.org/twiki/bin/view.pl/Main/STLDetailHashMaphttp://www.cppblog.com/guojingjia2006/archive/2008/01/12/41037.aspx两篇文章对解决我的问题帮了大忙,特将其内容贴出。

   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;
          };

     当然,这只是一个简单模型,C++标准库的泛型模版一向以嵌套复杂而闻名,初学时看类库,无疑天书啊。微软的hash_map类还聚合了hash_compare仿函数类,hash_compare类里有聚合了less仿函数类,乱七八糟的。

     下面说说使用方法:

     一、简单变量作为索引:整形、实性、指针型
     其实指针型也就是整形,算法一样。但是hash_map会对char*, const char*, wchar_t*, const wchar_t*做特殊处理。
     这种情况最简单,下面代码是整形示例:
            hash_map<int, int> IntHash;
            IntHash[1] = 123;
            IntHash[2] = 456;

            int val = IntHash[1];
            int val = IntHash[2];
     实型和指针型用法和整形一样,原理如下:
     1、使用简单类型作索引声明hash_map的时候,不需要声明模版的后两个参数(最后一个参数指名hash_map节点的存储方式,默认为pair,我觉得这就挺好,没必要修改),使用默认值就好。
     2、对于除过字符串的其它简单类型,hash_map使用模版函数 size_t hash_value(const _Kty& _Keyval) 计算hash值,计算方法是经典的掩码异或法,自动溢出得到索引hash值。微软的工程师也许开了一个玩笑,这个掩码被定义为0xdeadbeef(死牛肉,抑或是某个程序员的外号)。
     3、对于字符串指针作索引的时候,使用定类型函数inline size_t hash_value(const char *_Str)或inline size_t hash_value(const wchar_t *_Str)计算hash值,计算方法是取出每一个字符求和,自动溢出得到hash值。对于字符串型的hash索引,要注意需要自定义less仿函数。
     因为我们有理由认为,人们使用hash表进行快速查找的预期成本要比在hash表中插入的预期成本低得多,所以插入可以比查找昂贵些;基于这个假设,hash_map在有冲突时,插入链表是进行排序插入的,这样在进行查询冲突解决的时候就能够更快捷的找到需要的索引。
     但是,基于泛型编程的原则,hash_map也有理由认为每一种类型都支持使用"<"来判别两个类型值的大小,这种设计恰好让字符串类型无所适从,众所周知,两个字符串指针的大小并不代表字符串值的大小。见如下代码:
          hash_map<const char*, int> CharHash;
          CharHash["a"] = 123;
          CharHash["b"] = 456;

          char szInput[64] = "";
          scanf("%s", szInput);

          int val = CharHash[szInput];

     最终的结果就是无论输入任何字符串,都无法找到对应的整数值。因为输入的字符串指针是szInput指针,和"a"或"b"字符串常量指针的大小是绝对不会相同。解决方法如下:
     首先写一个仿函数CharLess,继承自仿函数基类binary_function(当然也可以不继承,这样写只是符合标准,而且写起来比较方便,不用被类似于指针的指针和指针的引用搞晕。

          struct CharLess : public binary_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);
               }
          };

     很好,有了这个仿函数,就可以正确的使用字符串指针型hash_map了。如下:

          hash_map<const char*, int, hash_compare<const char*, CharLess> > CharHash;
          CharHash["a"] = 123;
          CharHash["b"] = 456;

          char szInput[64] = "";
          scanf("%s", szInput);

          int val = CharHash[szInput];
      
     现在就可以正常工作了。至此,简单类型的使用方法介绍完毕。

     二、用户自定义类型:比如对象类型,结构体。
     这种情况比价复杂,我们先说简单的,对于C++标准库的string类。
      
     庆幸的是,微软为basic_string(string类的基类)提供了hash方法,这使得使用string对象做索引简单了许多。值得注意(也值得郁闷)的是,虽然支持string的hash,string类却没有重载比较运算符,所以标准的hash_compare仿函数依旧无法工作。我们继续重写less仿函数。
          
          struct string_less : public binary_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 : fase); 
               } 
          };
            
     好了,我们可以书写如下代码:
            
          hash_map<string, int, hash_compare<string, string_less> > StringHash;
          StringHash["a"] = 123;
          StringHash["b"] = 456;

          string strKey = "a";

          int val = CharHash[strKey];
      
     这样就可以了。
      
     对于另外的一个常用的字符串类CString(我认为微软的CString比标准库的string设计要洒脱一些)更加复杂一些。很显然,标准库里不包含对于CString的支持,但CString却重载了比较运算符(郁闷)。我们必须重写hash_compare仿函数。值得一提的是,在Virtual Stdio 2003中,CString不再是MFC的成员,而成为ATL的成员,使用#include <atlstr.h>就可以使用。我没有采用重写hash_compare仿函数的策略,而仅仅是继承了它,在模版库中的继承是没有性能损耗的,而且能让我偷一点懒。 
     首先重写一个hash_value函数:
      
          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); 
          }
      
     其次重写hash_compare仿函数:
      
          class CString_hash_compare : public hash_compare<CString> 
          { 
          public: 
               size_t operator()(const CString& _Key) const 
               { 
                    return((size_t)CString_hash_value(_Key));
               }
   
               bool operator()(const CString& _Keyval1, const CString& _Keyval2) const 
               { 
                    return (comp(_Keyval1, _Keyval2)); 
               } 
          };
            
     上面的重载忽略了基类对于less仿函数的引入,因为CString具备比较运算符,我们可以使用默认的less仿函数,在这里映射为comp。好了,我们可以声明新的hash_map对象如下:

          hash_map<CString, int, CString_hash_compare> CStringHash;

     其余的操作一样一样的。

     下来就说说对于自定义对象的使用方法:首先定义
      
          struct IHashable 
          { 
               virtual unsigned long hash_value() const = 0; 
               virtual bool operator < (const IHashable& val) const = 0; 
               virtual IHashable& operator = (const IHashable& val) = 0; 
          };
      
     让我们自写的类都派生自这里,有一个标准,接下来定义我们的类:
      
          class CTest : public IHashable 
          { 
          public: 
               int m_value; 
               CString m_message; 
          public: 
               CTest() : m_value(0) 
               { 
               }
            
               CTest(const CTest& obj) 
               { 
                    m_value = obj.m_value; 
                    m_message = obj.m_message; 
               } 
          public: 
               virtual IHashable& operator = (const IHashable& val) 
               { 
                    m_value   = ((CTest&)val).m_value; 
                    m_message = ((CTest&)val).m_message; 
                    return(*this); 
               }
            
               virtual unsigned long hash_value() const
               {
                    // 这里使用类中的m_value域计算hash值,也可以使用更复杂的函数计算所有域总的hash值
                    return(m_value ^ 0xdeadbeef  
               }
            
               virtual bool operator < (const IHashable& val) const 
               { 
                    return(m_value < ((CTest&)val).m_value); 
               } 
          };
      
     用这个类的对象做为hash索引准备工作如下,因为接口中规定了比较运算符,所以这里可以使用标准的less仿函数,所以这里忽略:
      
          template<class _Tkey> 
          class MyHashCompare : public hash_compare<_Tkey> 
          { 
          public: 
               size_t operator()(const _Tkey& _Key) const 
               { 
                    return(_Key.hash_value()); 
               }
            
               bool operator()(const _Tkey& _Keyval1, const _Tkey& _Keyval2) const 
               { 
                    return (comp(_Keyval1, _Keyval2)); 
               } 
          };
            
     下来就这样写:
      
          CTest test; 
          test.m_value = 123; 
          test.m_message = "This is a test";
      
          MyHash[test] = 2005;
            
          int val = MyHash[test];
      
     可以看到正确的数字被返回。
      
     三、关于hash_map的思考:
      
     1、性能分析:采用了内联代码和模版技术的hash_map在效率上应该是非常优秀的,但我们还需要注意如下几点:
      
     * 经过查看代码,字符串索引会比简单类型索引速度慢,自定义类型索引的性能则和我们选择hash的内容有很大关系,简单为主,这是使用hash_map的基本原则。 
     * 可以通过重写hash_compair仿函数,更改里面关于桶数量的定义,如果取值合适,也可以得到更优的性能。如果桶数量大于10,则牢记它应该是一个质数。 
     * 在自定义类型是,重载的等号(或者拷贝构造)有可能成为性能瓶颈,使用对象指针最为索引将是一个好的想法,但这就必须重写less仿函数,理由同使用字符串指针作为索引。

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

  

  1. #include <hash_map>  
  2. using namespace std;  
  3. using namespace stdext;  

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

  1.  class hash_map<class _Tkey, class _Tval>  
  2. {  
  3. private:  
  4.     typedef pair<_Tkey, _Tval> hash_pair;  
  5.     typedef list<hash_pair>    hash_list;  
  6.     typedef vector<hash_list>  hash_table;  
  7. };  


     当然,这只是一个简单模型,C++标准库的泛型模版一向以嵌套复杂而闻名,初学时看类库,无疑天书啊。微软的hash_map类还聚合了hash_compare仿函数类,hash_compare类里又聚合了less仿函数类,乱七八糟的。

     下面说说使用方法:

     一、简单变量作为索引:整形、实性、指针型
     其实指针型也就是整形,算法一样。但是hash_map会对char*, const char*, wchar_t*, const wchar_t*做特殊处理。
     这种情况最简单,下面代码是整形示例:
 

  1. hash_map<intint> IntHash;  
  2. IntHash[1] = 123;  
  3. IntHash[2] = 456;  
  4. int val = IntHash[1];  
  5. int val = IntHash[2];  

     实型和指针型用法和整形一样,原理如下:
     1、使用简单类型作索引声明hash_map的时候,不需要声明模版的后两个参数(最后一个参数指名hash_map节点的存储方式,默认为pair,我觉得这就挺好,没必要修改),使用默认值就好。
     2、对于除过字符串的其它简单类型,hash_map使用模版函数 size_t hash_value(const _Kty& _Keyval) 计算hash值,计算方法是经典的掩码异或法,自动溢出得到索引hash值。微软的工程师也许开了一个玩笑,这个掩码被定义为0xdeadbeef(死牛肉,抑或是某个程序员的外号)。
     3、对于字符串指针作索引的时候,使用定类型函数inline size_t hash_value(const char *_Str)或inline size_t hash_value(const wchar_t *_Str)计算hash值,计算方法是取出每一个字符求和,自动溢出得到hash值。对于字符串型的hash索引,要注意需要自定义less仿函数。
     因为我们有理由认为,人们使用hash表进行快速查找的预期成本要比在hash表中插入的预期成本低得多,所以插入可以比查找昂贵些;基于这个假设,hash_map在有冲突时,插入链表是进行排序插入的,这样在进行查询冲突解决的时候就能够更快捷的找到需要的索引。
     但是,基于泛型编程的原则,hash_map也有理由认为每一种类型都支持使用"<"来判别两个类型值的大小,这种设计恰好让字符串类型无所适从,众所周知,两个字符串指针的大小并不代表字符串值的大小。见如下代码:

  1. hash_map<const char*, int> CharHash;  
  2. CharHash["a"] = 123;  
  3. CharHash["b"] = 456;  
  4. char szInput[64] = "";  
  5. scanf("%s", szInput);  
  6. int val = CharHash[szInput];  

     最终的结果就是无论输入任何字符串,都无法找到对应的整数值。因为输入的字符串指针是szInput指针,和"a"或"b"字符串常量指针的大小是绝对不会相同。解决方法如下:
     首先写一个仿函数CharLess,继承自仿函数基类binary_function(当然也可以不继承,这样写只是符合标准,而且写起来比较方便,不用被类似于指针的指针和指针的引用搞晕。

          

  1. struct CharLess : public binary_function<const char*, const char*, bool>  
  2. {  
  3. public:  
  4.     result_type operator()(const first_argument_type& _Left, const second_argument_type& _Right) const  
  5.     {  
  6.         return(stricmp(_Left, _Right) < 0 ? true : false);  
  7.     }  
  8. };  

     很好,有了这个仿函数,就可以正确的使用字符串指针型hash_map了。如下:

         

  1. hash_map<const char*, int, hash_compare<const char*, CharLess> > CharHash;  
  2. CharHash["a"] = 123;  
  3. CharHash["b"] = 456;  
  4. char szInput[64] = "";  
  5. scanf("%s", szInput);  
  6. int val = CharHash[szInput];  

     现在就可以正常工作了。至此,简单类型的使用方法介绍完毕。

     二、用户自定义类型:比如对象类型,结构体。
     这种情况比价复杂,我们先说简单的,对于C++标准库的string类。
      
     庆幸的是,微软为basic_string(string类的基类)提供了hash方法,这使得使用string对象做索引简单了许多。值得注意(也值得郁闷)的是,虽然支持string的hash,string类却没有重载比较运算符,所以标准的hash_compare仿函数依旧无法工作。我们继续重写less仿函数。
          
[cpp] view plaincopy

  1.  struct string_less : public binary_function<const string, const string, bool>  
  2. {   
  3. public:   
  4.     result_type operator()(const first_argument_type& _Left, const second_argument_type& _Right) const   
  5.     {   
  6.         return(_Left.compare(_Right) < 0 ? true : fase);   
  7.     }   
  8. };  
            
     好了,我们可以书写如下代码:
             
  1. hash_map<string, int, hash_compare<string, string_less> > StringHash;  
  2. StringHash["a"] = 123;  
  3. StringHash["b"] = 456;  
  4. string strKey = "a";  
  5. int val = CharHash[strKey];   

     这样就可以了。
      
     对于另外的一个常用的字符串类CString(我认为微软的CString比标准库的string设计要洒脱一些)更加复杂一些。很显然,标准库里不包含对于CString的支持,但CString却重载了比较运算符(郁闷)。我们必须重写hash_compare仿函数。值得一提的是,在Virtual Stdio 2003中,CString不再是MFC的成员,而成为ATL的成员,使用#include <atlstr.h>就可以使用。我没有采用重写hash_compare仿函数的策略,而仅仅是继承了它,在模版库中的继承是没有性能损耗的,而且能让我偷一点懒。
     首先重写一个hash_value函数:
      
        

  1. inline size_t CString_hash_value(const CString& str)   
  2. {   
  3.     size_t value = _HASH_SEED;   
  4.     size_t size  = str.GetLength();   
  5.     if (size > 0) {   
  6.         size_t temp = (size / 16) + 1;   
  7.         size -= temp;   
  8.         for (size_t idx = 0; idx <= size; idx += temp) {   
  9.             value += (size_t)str[(int)idx];   
  10.         }   
  11.     }   
  12.     return(value);   
  13. }  
其次重写hash_compare仿函数:
      
         
  1. class CString_hash_compare : public hash_compare<CString>   
  2. {   
  3. public:   
  4.     size_t operator()(const CString& _Key) const   
  5.     {   
  6.         return((size_t)CString_hash_value(_Key));  
  7.     }  
  8.      
  9.     bool operator()(const CString& _Keyval1, const CString& _Keyval2) const   
  10.     {   
  11.         return (comp(_Keyval1, _Keyval2));   
  12.     }   
  13. };  


            
     上面的重载忽略了基类对于less仿函数的引入,因为CString具备比较运算符,我们可以使用默认的less仿函数,在这里映射为comp。好了,我们可以声明新的hash_map对象如下:

          

  1. hash_map<CString, int, CString_hash_compare> CStringHash;  

     其余的操作一样一样的。

     下来就说说对于自定义对象的使用方法:首先定义
      
         

  1. struct IHashable   
  2.    
  3.    virtual unsigned long hash_value() const = 0;   
  4.    virtual bool operator < (const IHashable& val) const = 0;   
  5.    virtual IHashable& operator = (const IHashable& val) = 0;   
  6. ;  


      
     让我们自写的类都派生自这里,有一个标准,接下来定义我们的类:
      
        
  1. class CTest : public IHashable   
  2. {   
  3. public:   
  4.     int m_value;   
  5.     CString m_message;   
  6. public:   
  7.     CTest() : m_value(0) {}  
  8.               
  9.     CTest(const CTest& obj)   
  10.     {   
  11.         m_value = obj.m_value;   
  12.         m_message = obj.m_message;   
  13.     }   
  14. public:   
  15.     virtual IHashable& operator = (const IHashable& val) {   
  16.         m_value   = ((CTest&)val).m_value;   
  17.         m_message = ((CTest&)val).m_message;   
  18.         return(*this);   
  19.     }  
  20.               
  21.     virtual unsigned long hash_value() const {  
  22.         // 这里使用类中的m_value域计算hash值,也可以使用更复杂的函数计算所有域总的hash值  
  23.         return(m_value ^ 0xdeadbeef    
  24.     }  
  25.               
  26.     virtual bool operator < (const IHashable& val) const {   
  27.         return(m_value < ((CTest&)val).m_value);   
  28.     }   
  29. };  

      
     用这个类的对象做为hash索引准备工作如下,因为接口中规定了比较运算符,所以这里可以使用标准的less仿函数,所以这里忽略:
      
         
  1. template<class _Tkey>   
  2. class MyHashCompare : public hash_compare<_Tkey>   
  3. {   
  4. public:   
  5.     size_t operator()(const _Tkey& _Key) const {   
  6.         return(_Key.hash_value());   
  7.     }  
  8.   
  9.   
  10.     bool operator()(const _Tkey& _Keyval1, const _Tkey& _Keyval2) const {   
  11.         return (comp(_Keyval1, _Keyval2));   
  12.     }   
  13. };  
  14.               


     下来就这样写:
     
  1. CTest test;   
  2. test.m_value = 123;   
  3. test.m_message = "This is a test";  
  4.   
  5.   
  6. MyHash[test] = 2005;  
  7.   
  8.   
  9. int val = MyHash[test];  

      
     可以看到正确的数字被返回。
      
     三、关于hash_map的思考:
      
     1、性能分析:采用了内联代码和模版技术的hash_map在效率上应该是非常优秀的,但我们还需要注意如下几点:
      
     * 经过查看代码,字符串索引会比简单类型索引速度慢,自定义类型索引的性能则和我们选择hash的内容有很大关系,简单为主,这是使用hash_map的基本原则。
     * 可以通过重写hash_compair仿函数,更改里面关于桶数量的定义,如果取值合适,也可以得到更优的性能。如果桶数量大于10,则牢记它应该是一个质数。
     * 在自定义类型是,重载的等号(或者拷贝构造)有可能成为性能瓶颈,使用对象指针最为索引将是一个好的想法,但这就必须重写less仿函数,理由同使用字符串指针作为索引。

 

自己使用上面的方法成功解决了使用PTCHAR作为Key的使用,其解决方法如下:

 

  1. inline size_t PTCHAR_hash_value(const PTCHAR str)  
  2. {  
  3.     size_t value = _HASH_SEED;  
  4.     size_t size = _tcslen(str);  
  5.     if (size > 0) {  
  6.         size_t temp = (size/16) + 1;  
  7.         size -= temp;  
  8.         for (size_t idx=0; idx<=size; idx+=temp) {  
  9.             value += (size_t)str[(int)idx];  
  10.         }  
  11.     }  
  12.     return value;  
  13. }  
  14. class PTCHAR_hash_compare : public stdext::hash_compare<PTCHAR>  
  15. {  
  16. public:  
  17.     size_t operator()(const PTCHAR _Key) const {  
  18.         return ((size_t)PTCHAR_hash_value(_Key));  
  19.     }  
  20.     bool operator()(const PTCHAR _Keyval1, const PTCHAR _Keyval2) const {  
  21.         return (_tcscmp(_Keyval1, _Keyval2));  
  22.     }  
  23. };  
  24. stdext::hash_map<PTCHARlong, PTCHAR_hash_compare > myHash;  

hash_map原理及C++实现

标签:

原文地址:http://blog.csdn.net/gggg_ggg/article/details/46602969

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!