一个高效的hash str map 的实现

       在使用hash_map 的过程中,发现 hash_map 对字符串做为键值支持的不是很好, 就特意写了一个新的 StrMap, 主要用做字符串型键值的Map,经过简单的测试,设置和提取键值是hash_map的20倍左右,现在拿出来给大家分享, 也希大家提出更新的修改意见。谢谢。

 

 

下面的代码是 StrMap的实现代码。

 

  1. #pragma once  
  2.   
  3. /// hash str map   
  4. /** 
  5.     /brief 利用 hash 算法实现,定长字符串的map 
  6. */  
  7. template<typename _T, int _STR_LEN = 128>  
  8. class StrMap  
  9. {  
  10. protected:  
  11.     struct Assoc  
  12.     {  
  13.         char    m_key[_STR_LEN];  
  14.         _T      m_data;  
  15.         Assoc*  m_pNext;  
  16.     };  
  17.   
  18.     typedef Assoc* LPAssoc;   
  19. public:  
  20.     /// 迭代器结构体  
  21.     struct iterator   
  22.     {  
  23.         friend class StrMap;  
  24.   
  25.         iterator()  
  26.         {  
  27.             m_pMap = NULL;  
  28.             m_pIter = NULL ;  
  29.             m_nIndex = 0;  
  30.         }  
  31.   
  32.         iterator& operator ++()       
  33.         {  
  34.             if ( m_pIter->m_pNext )   
  35.             {  
  36.                 m_pIter = m_pIter->m_pNext;  
  37.                 return *this;  
  38.             }  
  39.   
  40.             for ( ULONG i=m_nIndex+1; i<m_pMap->m_nHashTableSize; ++i)   
  41.             {  
  42.                 if ( m_pMap->m_pHashTable[i] )  
  43.                 {  
  44.                     m_pIter = m_pMap->m_pHashTable[i];  
  45.                     m_nIndex = i;  
  46.                     return *this;  
  47.                 }                 
  48.             }  
  49.   
  50.             m_pIter = NULL ;  
  51.             m_nIndex = 0;  
  52.             return *this;  
  53.         }   
  54.   
  55.         iterator operator ++(int)     
  56.         {  
  57.             iterator tmp( m_pMap, m_pIter, m_nIndex);  
  58.   
  59.             if ( m_pIter->m_pNext )   
  60.             {  
  61.                 m_pIter = m_pIter->m_pNext;  
  62.                 return tmp;  
  63.             }  
  64.   
  65.             for ( ULONG i=m_nIndex+1; i<m_pMap->m_nHashTableSize; ++i)   
  66.             {  
  67.                 if ( m_pMap->m_pHashTable[i] )  
  68.                 {  
  69.                     m_pIter = m_pMap->m_pHashTable[i];  
  70.                     m_nIndex = i;  
  71.                     return tmp;  
  72.                 }                 
  73.             }  
  74.   
  75.             m_pIter = NULL ;  
  76.             m_nIndex = 0;  
  77.             return tmp;  
  78.         }   
  79.   
  80.         _T* operator ->()  
  81.         {  
  82.             return &(m_pIter->m_data) ;  
  83.         }  
  84.   
  85.         _T& operator *()  
  86.         {  
  87.             return m_pIter->m_data ;  
  88.         }  
  89.   
  90.         bool operator != (const iterator & obj )   
  91.         {  
  92.             return m_pMap != obj.m_pMap || m_pIter != obj.m_pIter ;  
  93.         }  
  94.         bool operator == (const iterator & obj )   
  95.         {  
  96.             return m_pMap == obj.m_pMap && m_pIter == obj.m_pIter ;  
  97.         }  
  98.   
  99.     protected:  
  100.   
  101.         iterator(StrMap* pMap, LPAssoc pAssoc = NULL, ULONG nIndex = 0)   
  102.         {  
  103.             m_pMap = pMap;  
  104.             m_pIter = pAssoc ;  
  105.             m_nIndex = nIndex;  
  106.         }  
  107.   
  108.         LPAssoc m_pIter ;  
  109.         ULONG m_nIndex ;  
  110.         StrMap* m_pMap;  
  111.     };  
  112.   
  113. public:  
  114.     ///构造方法  
  115.     /** 
  116.         /param ULONG nSize =199         哈希表默认的初始大小 
  117.         /param bool bAutoIncr = true    哈希表是否自动增加 
  118.     */  
  119.     StrMap(ULONG nSize = 199, bool bAutoIncr = true)  
  120.     {  
  121.         m_pHashTable = NULL ;  
  122.         m_nHashTableSize = 0;  
  123.         m_bAutoIncr = bAutoIncr;  
  124.         m_nCount = 0 ;  
  125.         m_nMaxLength = _STR_LEN ;   
  126.         InitMap(nSize);  
  127.     }  
  128.       
  129.     ///析构方法  
  130.     virtual ~StrMap(void)  
  131.     {  
  132.         Destory();  
  133.     }  
  134.   
  135.     /// 查找某个元素是否存在  
  136.     /** 
  137.         /param const char * pKey    关键字 
  138.         /param _T& obj              元素的数据值 
  139.         /return bool 是否查找正确 
  140.     */  
  141.     bool Find(const char * pKey, _T & obj)  
  142.     {  
  143.         if ( NULL == pKey )  
  144.         {  
  145.             return false;  
  146.         }  
  147.         if ( strlen(pKey) > m_nMaxLength )   
  148.         {  
  149.             return false ;  
  150.         }  
  151.   
  152.         for(LPAssoc pAssoc = m_pHashTable[HashKey(pKey)%m_nHashTableSize] ;  
  153.             pAssoc;   
  154.             pAssoc = pAssoc->m_pNext )  
  155.         {  
  156.             if ( 0 == strcmp(pAssoc->m_key, pKey) )  
  157.             {  
  158.                 obj = pAssoc->m_data ;  
  159.                 return true;  
  160.             }             
  161.         }  
  162.   
  163.         return false;  
  164.     }  
  165.   
  166.     /// 查找某个元素是否存在  
  167.     /** 
  168.         /param const char* pKey 输入的字符串 
  169.         /return bool 是否包含 pKey  
  170.     */  
  171.     bool Contains(const char* pKey)  
  172.     {  
  173.         if ( NULL == pKey )  
  174.         {  
  175.             return false;  
  176.         }  
  177.         if ( strlen(pKey) > m_nMaxLength )   
  178.         {  
  179.             return false ;  
  180.         }  
  181.   
  182.         for(LPAssoc pAssoc = m_pHashTable[HashKey(pKey)%m_nHashTableSize] ;  
  183.             pAssoc;   
  184.             pAssoc = pAssoc->m_pNext )  
  185.         {  
  186.             if ( 0 == strcmp(pAssoc->m_key, pKey) )  
  187.             {  
  188.                 return true;  
  189.             }             
  190.         }  
  191.   
  192.         return false;  
  193.     }  
  194.   
  195.     /// 设置一个key   
  196.     /** 
  197.         /param const char* pKey     要设置的键值 
  198.         /param const _T & obj       键值对应的值 
  199.     */  
  200.     bool Set(const char * pKey, const _T & obj)   
  201.     {  
  202.         if( NULL == pKey )  
  203.         {  
  204.             return false;  
  205.         }  
  206.         if ( strlen(pKey) >= m_nMaxLength )   
  207.         {  
  208.             return false ;  
  209.         }  
  210.   
  211.         ULONG nHashKey = HashKey(pKey)%m_nHashTableSize ;  
  212.   
  213.         if ( NULL == m_pHashTable[nHashKey] )  
  214.         {  
  215.             //新建一个  
  216.             m_pHashTable[nHashKey] = new Assoc ;  
  217.             strcpy(m_pHashTable[nHashKey]->m_key, pKey);  
  218.             m_pHashTable[nHashKey]->m_data = obj;  
  219.             m_pHashTable[nHashKey]->m_pNext = NULL;  
  220.             ++m_nCount;  
  221.         }  
  222.         else  //查找有没有相等的  
  223.         {  
  224.             LPAssoc pAssoc = m_pHashTable[nHashKey] ;  
  225.             LPAssoc pPervAssoc = pAssoc;  
  226.             while( pAssoc )  
  227.             {  
  228.                 if ( strcmp(pAssoc->m_key, pKey) == 0 )  
  229.                 {  
  230.                     pAssoc->m_data = obj;  
  231.                     break;  
  232.                 }  
  233.                 pPervAssoc = pAssoc;  
  234.                 pAssoc = pAssoc->m_pNext;  
  235.             }  
  236.             if( NULL == pAssoc)  
  237.             {  
  238.                 pAssoc = pPervAssoc->m_pNext = new Assoc;  
  239.                 strcpy(pAssoc->m_key, pKey);  
  240.                 pAssoc->m_data = obj;  
  241.                 pAssoc->m_pNext = NULL;  
  242.                 ++m_nCount;  
  243.             }  
  244.         }  
  245.   
  246.         if ( (m_nCount > m_nHashTableSize) && m_bAutoIncr )  
  247.         {  
  248.             ReSetTableSize( AdjustSize(m_nCount));  
  249.         }  
  250.   
  251.         return true;  
  252.     }  
  253.   
  254.     /// 从哈希表里面删除一个键值  
  255.     /** 
  256.         /param const char* pKey 要删除的 key  
  257.     */  
  258.     void RemoveKey(const char * pKey)  
  259.     {  
  260.         if( NULL == pKey )  
  261.             return ;  
  262.   
  263.         ULONG nHashKey = HashKey(pKey)%m_nHashTableSize ;  
  264.         LPAssoc pAssoc =  m_pHashTable[nHashKey];   
  265.   
  266.         if ( pAssoc && (strcmp( pAssoc->m_key, pKey)==0))  
  267.         {  
  268.             m_pHashTable[nHashKey] = pAssoc->m_pNext ;  
  269.             delete pAssoc;  
  270.             -- m_nCount;  
  271.         }  
  272.         else if ( pAssoc )  
  273.         {  
  274.             LPAssoc pPrevAssoc = pAssoc ;  
  275.             pAssoc = pAssoc->m_pNext;  
  276.             while ( pAssoc )  
  277.             {  
  278.                 if ( strcmp( pAssoc->m_key, pKey) == 0 )  
  279.                 {  
  280.                     pPrevAssoc->m_pNext = pAssoc->m_pNext;  
  281.                     delete pAssoc;  
  282.                     --m_nCount;  
  283.                     break ;  
  284.                 }  
  285.                 pPrevAssoc = pAssoc ;  
  286.                 pAssoc = pAssoc->m_pNext;  
  287.             }  
  288.         }  
  289.     }  
  290.   
  291.     /// 清空map  
  292.     /** 
  293.         /brief 清空 map 里面的数据,但是并不销毁哈希表所分配的内存。 
  294.     */  
  295.     void Clear()  
  296.     {  
  297.         LPAssoc pAssoc ;  
  298.         LPAssoc pDelAssoc ;  
  299.         for ( ULONG i=0; i<m_nHashTableSize; ++i)   
  300.         {  
  301.             pAssoc = m_pHashTable[i];  
  302.             while( pAssoc )   
  303.             {  
  304.                 pDelAssoc = pAssoc ;                  
  305.                 pAssoc = pAssoc->m_pNext;  
  306.                 delete pDelAssoc;  
  307.             }  
  308.             m_pHashTable[i] = NULL;       
  309.         }  
  310.         m_nCount = 0;  
  311.     }  
  312.   
  313.     /// 返加前数据元素的个数  
  314.     ULONG Size()  
  315.     {  
  316.         return m_nCount;  
  317.     }  
  318.   
  319.     /// 得到迭代器的开始  
  320.     iterator Begin()   
  321.     {  
  322.         for ( ULONG i=0; i<m_nHashTableSize; ++i)   
  323.         {  
  324.             if ( m_pHashTable[i] )  
  325.             {  
  326.                 return iterator(this, m_pHashTable[i], i);  
  327.             }  
  328.         }  
  329.         return iterator(this, NULL, 0);  
  330.     }  
  331.   
  332.     /// 迭代器的结束  
  333.     iterator End()  
  334.     {         
  335.         return iterator(this, NULL, 0);  
  336.     }  
  337. protected:  
  338.   
  339.   
  340.     bool InitMap(ULONG nSize)  
  341.     {  
  342.         m_nHashTableSize = AdjustSize(nSize);  
  343.   
  344.         if (m_pHashTable)  
  345.         {  
  346.             delete [] m_pHashTable;  
  347.             m_pHashTable = NULL ;  
  348.         }  
  349.         m_pHashTable = new LPAssoc[m_nHashTableSize];  
  350.         memset( m_pHashTable, 0 , sizeof( LPAssoc) * m_nHashTableSize);  
  351.   
  352.         return true;  
  353.     }  
  354.   
  355.   
  356.   
  357.     /// 重新设置哈希表的大小  
  358.     /** 
  359.     /param ULONG nSize 新的哈希表的大小 
  360.     /param bool 是否成功 
  361.     */  
  362.     bool ReSetTableSize(ULONG nSize)  
  363.     {  
  364.         LPAssoc* pNewTable ;   
  365.         pNewTable = new LPAssoc[nSize];  
  366.         memset(pNewTable, 0, sizeof(LPAssoc) * nSize );  
  367.         ULONG nHashKey ;  
  368.         LPAssoc pNewAssoc, pOldAssoc ;  
  369.   
  370.         for ( ULONG i=0; i<m_nHashTableSize; ++i)   
  371.         {  
  372.             pOldAssoc = m_pHashTable[i] ;  
  373.             while( pOldAssoc )   
  374.             {  
  375.                 nHashKey = HashKey( pOldAssoc->m_key ) % nSize ;  
  376.                 pNewAssoc = pNewTable[nHashKey];  
  377.   
  378.                 if ( pNewAssoc == NULL )   
  379.                 {  
  380.                     pNewTable[nHashKey] = pOldAssoc;  
  381.                     pOldAssoc = pNewTable[nHashKey]->m_pNext;  
  382.                     pNewTable[nHashKey]->m_pNext = NULL;  
  383.                 }  
  384.                 else  
  385.                 {  
  386.                     while ( NULL != pNewAssoc->m_pNext )   
  387.                         pNewAssoc = pNewAssoc->m_pNext;   
  388.                     pNewAssoc->m_pNext = pOldAssoc ;   
  389.                     pOldAssoc = pOldAssoc->m_pNext;  
  390.                     pNewAssoc->m_pNext->m_pNext = NULL ;  
  391.                 }  
  392.             }  
  393.         }  
  394.   
  395.         delete [] m_pHashTable ;   
  396.         m_pHashTable = pNewTable ;  
  397.         m_nHashTableSize = nSize;  
  398.         return true;  
  399.     }  
  400.   
  401.   
  402.     /// 计算字符串的哈希值  
  403.     /** 
  404.         /param const char* key  字符串 
  405.         /param ULONG 哈希值 
  406.     */  
  407.     ULONG HashKey(const char* key)   
  408.     {  
  409.         if ( NULL == key )  
  410.             return 0;  
  411.         ULONG nHash = 0;  
  412.         while (*key)  
  413.             nHash = (nHash<<5) + nHash + *key++;  
  414.         return nHash;  
  415.     }  
  416.   
  417.     /// 根据当前的大小,调整新的哈希表的大小  
  418.     /** 
  419.         /param ULONG nSize 老的表的大小 
  420.         /return ULONG 返回新的表大小 
  421.     */  
  422.     ULONG AdjustSize(ULONG nSize)  
  423.     {  
  424.         const ULONG prime_list[] =  
  425.         {  
  426.                 53,         97,             193,        389,        769,  
  427.                 1543,       3079,           6151,       12289,      24593,  
  428.                 49157,      98317,          196613,     393241,     786443,  
  429.                 1572869,    3145739,        6291469,    12582917,   25165842,  
  430.                 50331553,   100663319,      201326611,  402653189,  805306457,  
  431.                 1610612741, 3221225473ul,   4294967291ul  
  432.         };  
  433.   
  434.         int nArrSize  = sizeof(prime_list) / sizeof(prime_list[0]);  
  435.         int i;    
  436.         for ( i=0; i<nArrSize; ++i)  
  437.         {  
  438.             if ( prime_list[i] >= nSize )  
  439.                 break ;  
  440.         }  
  441.         if ( i == nArrSize )   
  442.             --i;  
  443.   
  444.         return prime_list[i];  
  445.     }  
  446.   
  447.     // 销毁map包括分配的内存。  
  448.     void Destory()  
  449.     {  
  450.         Clear();  
  451.         delete [] m_pHashTable ;  
  452.         m_pHashTable = NULL ;  
  453.         m_nHashTableSize = 0;  
  454.     }  
  455.   
  456. private:  
  457.     /// 为了安全,不能直接调用S拷贝构造方法  
  458.     StrMap(const StrMap& obj)  
  459.     {  
  460.         //nothing  
  461.     }  
  462.   
  463.     /// 为了安全,不能调用赋值方法  
  464.     StrMap& operator = (const StrMap&obj)  
  465.     {  
  466.         //nothing  
  467.         return *this ;  
  468.     }  
  469.   
  470. protected:  
  471.     LPAssoc* m_pHashTable ;             ///< 哈希表的地址指针  
  472.     ULONG   m_nHashTableSize;           ///< 表大小  
  473.     ULONG   m_nCount ;                  ///< 当前数据元素的个数  
  474.     bool    m_bAutoIncr;                ///< 自动增长  
  475.     ULONG   m_nMaxLength;               //< 字符串的最大长度   
  476. };  

 

 

下面的代码是 StrMap 的测试以及和hash_map 的性能比较的代码。

 

  1. #include "stdafx.h"  
  2. #include <iostream>  
  3. #include "StrMap.h"  
  4.   
  5. #include <string>  
  6. #include <list>  
  7. #include <hash_map>  
  8. using namespace std ;   
  9.   
  10. void CompMap(int nItemCount )  
  11. {  
  12.   
  13.     printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++/n");   
  14.     printf("开始测试 %ld 个数据的设置。/n", nItemCount);  
  15.   
  16.   
  17.     StrMap<int> map;   
  18.     std::hash_map<string, int> hashMap ;  
  19.   
  20.     list<string> listStr ;  
  21.     char buf[128];  
  22.     int len ;  
  23.       
  24.     ULONG beg = ::GetTickCount();  
  25.     for ( ULONG i=0; i<nItemCount; ++i)  
  26.     {  
  27.         len = rand()%14 + 1;   
  28.         for ( int j=0; j<len; ++j)  
  29.         {  
  30.             buf[j] = rand() % 26 + 'a';  
  31.         }  
  32.         buf[len] = 0 ;   
  33.         listStr.push_back(buf);  
  34.     }  
  35.     printf("构造字符串用时:/t%d/n", ::GetTickCount()- beg);  
  36.   
  37.   
  38.     // test my map   
  39.     list<string>::iterator iter = listStr.begin();  
  40.     beg = ::GetTickCount();   
  41.     while (iter != listStr.end())  
  42.     {  
  43.         map.Set(iter->c_str(), 12);  
  44.         ++iter ;  
  45.     }  
  46.     printf("设置 StrMap 用时:/t%d/n", ::GetTickCount()-beg);      
  47.       
  48.     iter = listStr.begin();  
  49.     beg = ::GetTickCount();   
  50.     while (iter != listStr.end())  
  51.     {  
  52.         hashMap[(*iter) ]  = 12 ;  
  53.         ++iter ;  
  54.     }  
  55.     printf("设置 hash_map 用时:/t%d/n", ::GetTickCount()-beg);    
  56.   
  57.   
  58.     iter = listStr.begin();  
  59.    
  60.     int t;  
  61.     int nIndex = 0;  
  62.     int nFind = 0;  
  63.     int nLost =0;  
  64.   
  65.     beg = GetTickCount();  
  66.     iter = listStr.begin();  
  67.     while (iter != listStr.end())  
  68.     {  
  69.         if (map.Contains(iter->c_str()) )  
  70.             ++nFind;  
  71.         else   
  72.             ++nLost;  
  73.   
  74.         ++nIndex;  
  75.         ++iter ;  
  76.     }  
  77.     printf("遍历查找 strMap Key 用时:/t%d/n", ::GetTickCount() - beg);  
  78.     printf("查询次数 %d /t 查询到 %d次/t 丢失 %d/n", nIndex, nFind, nLost);  
  79.   
  80.   
  81.     nIndex = 0;  
  82.     nFind = 0;  
  83.     nLost =0;  
  84.   
  85.     beg = GetTickCount();  
  86.     iter = listStr.begin();  
  87.     while (iter != listStr.end())  
  88.     {         
  89.         if ( hashMap.find( (*iter)) != hashMap.end() )  
  90.             ++nFind;  
  91.         else   
  92.             ++nLost;  
  93.   
  94.         ++nIndex;  
  95.         ++iter ;  
  96.     }  
  97.     printf("遍历查找 hash_map Key 用时:/t%d/n", ::GetTickCount() - beg);  
  98.     printf("查询次数 %d /t 查询到 %d次/t 丢失 %d/n", nIndex, nFind, nLost);  
  99.   
  100.     beg = GetTickCount();  
  101.     StrMap<int>::iterator iterStrMap = map.Begin();   
  102.     nIndex = 0;  
  103.     while (  iterStrMap != map.End() )  
  104.     {  
  105.         ++ nIndex;  
  106.         ++ iterStrMap;  
  107.     }  
  108.     printf("遍历 strMap 用时:/t%d/t 查找到个数:%ld/n", ::GetTickCount() - beg, nIndex );  
  109.   
  110.   
  111.     beg = GetTickCount();  
  112.     std::hash_map<string, int>::iterator iterHashMap = hashMap.begin();   
  113.     nIndex = 0;  
  114.     while (  iterHashMap != hashMap.end() )  
  115.     {  
  116.         ++ nIndex;  
  117.         ++ iterHashMap;  
  118.     }  
  119.     printf("遍历 hash_map 用时:/t%d/t 查找到个数:%ld/n", ::GetTickCount() - beg, nIndex );  
  120.   
  121. }  
  122.   
  123.   
  124. int main(int argc, char* argv[])  
  125. {  
  126.     CompMap(1000);  
  127.     CompMap(10000);  
  128.     CompMap(20000);  
  129.   
  130.     return 0;  
  131.   
  132. }  

 

 

比较的结果:

 

  1. +++++++++++++++++++++++++++++++++++++++++++++++++++++++  
  2. 开始测试 1000 个数据的设置。  
  3. 构造字符串用时: 15  
  4. 设置 StrMap 用时:       0  
  5. 设置 hash_map 用时:     32  
  6. 遍历查找 strMap Key 用时:       0  
  7. 查询次数 1000    查询到 1000次   丢失 0  
  8. 遍历查找 hash_map Key 用时:     15  
  9. 查询次数 1000    查询到 1000次   丢失 0  
  10. 遍历 strMap 用时:       0        查找到个数:950  
  11. 遍历 hash_map 用时:     0        查找到个数:950  
  12. +++++++++++++++++++++++++++++++++++++++++++++++++++++++  
  13. 开始测试 10000 个数据的设置。  
  14. 构造字符串用时: 63  
  15. 设置 StrMap 用时:       15  
  16. 设置 hash_map 用时:     344  
  17. 遍历查找 strMap Key 用时:       16  
  18. 查询次数 10000   查询到 10000次  丢失 0  
  19. 遍历查找 hash_map Key 用时:     156  
  20. 查询次数 10000   查询到 10000次  丢失 0  
  21. 遍历 strMap 用时:       0        查找到个数:9011  
  22. 遍历 hash_map 用时:     0        查找到个数:9011  
  23. +++++++++++++++++++++++++++++++++++++++++++++++++++++++  
  24. 开始测试 20000 个数据的设置。  
  25. 构造字符串用时: 110  
  26. 设置 StrMap 用时:       47  
  27. 设置 hash_map 用时:     1296  
  28. 遍历查找 strMap Key 用时:       32  
  29. 查询次数 20000   查询到 20000次  丢失 0  
  30. 遍历查找 hash_map Key 用时:     468  
  31. 查询次数 20000   查询到 20000次  丢失 0  
  32. 遍历 strMap 用时:       0        查找到个数:17797  
  33. 遍历 hash_map 用时:     16       查找到个数:17797  
  34. Press any key to continue  

 转自http://blog.csdn.net/Bsq28/article/details/5826554

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值