分享

C 实现哈希表 HashMap冲突链式解决

 闲来看看 2013-02-25

C++实现哈希表 HashMap冲突链式解决

简述:

考虑到有大量数据的情况,所以使用Hash表

使用泛型实现

TypeA 是Key的类型,TypeB 是value的类型


1. 主要函数

1). TypeB Put(HashNode<TypeA,TypeB> 函数用来加入一个新的MapNode

2). TypeB Delete(const TypeA& key) 用来删除一个键值为key的节点

3). TypeB GetValue(const  TypeA& key) 通过key值来搜寻他的value


2. 主要算法

1) 使用一个函数类型指向用户定义的哈希值计算函数,这里我用了GetKeyValue_1这个平方取中法

2)使用链式法解决冲突,首先是一个节点指针数组,table[index] ,其中index是哈希函数计算出来的

如果由于键值传入哈希函数后计算出同一个index值,那么就以table[index]为头节点,横向建立链表避免冲突


3.类实现以及测试代码

HashMap.cpp


  1. ///***************************HashMap****************************/  
  2. //1.用数组形式建立哈希表  
  3. //2.使用链式方法解决冲突  
  4. //3.平方取中法通过字符串Hash函数求hash值(还有很多种其他的hash函数)  
  5. #include <iostream>  
  6. #include <string>  
  7. #include <cstring>  
  8. #include <stdlib.h>  
  9. #include <time.h>  
  10.   
  11. using namespace std;  
  12.   
  13. typedef unsigned long(*GetKeyValue)(const string& );  
  14.   
  15. //该类用来处理冲突的节点  
  16. template<class TypeA,class TypeB>  
  17. struct HashNode{  
  18.     TypeA key;  
  19.     TypeB value;  
  20.     HashNode *next;  
  21.     HashNode(TypeA key,TypeB value){  
  22.         HashNode::key = key;  
  23.         HashNode::value = value;  
  24.         next = NULL;  
  25.     }  
  26.     HashNode& operator=(const HashNode& node){  
  27.         key = node.key;  
  28.         value = node.key;  
  29.         next = node.next;  
  30.         return *this;  
  31.     }  
  32. };  
  33.   
  34.   
  35. //该类是HashMap用来存放hash表  
  36. template<class TypeA,class TypeB,class FuncType>  
  37. class HashMap{  
  38.     HashNode<TypeA,TypeB> **table;  
  39.     unsigned long capacity;  
  40.     FuncType GetKeyValue;  
  41.     const TypeB TYPEB_NULL;  
  42. public:  
  43.     HashMap(FuncType func,const TypeB& _null);  
  44.     ~HashMap();  
  45.     TypeB Put(const HashNode<TypeA,TypeB>& hashNode);  //插入一个HashNode 返回该节点的value值  
  46.     TypeB GetValue(const TypeA& key);  // 查找某个hashNode 其key为“key“的元素  
  47.     TypeB Delete(const TypeA& key);  // 查找某个hashNode 其key为“key“的元素  
  48. };  
  49.   
  50.   
  51. template<class TypeA,class TypeB,class FuncType> //在调用的时候指定函数  
  52. HashMap<TypeA,TypeB,FuncType>::HashMap(FuncType func,const TypeB& _null) : TYPEB_NULL(_null){  
  53.     capacity = 10000000;  
  54.     GetKeyValue = func;  
  55.     table = new HashNode<TypeA,TypeB>*[capacity];  
  56.     for(unsigned i = 0;i < capacity;i++)  
  57.         table[i] = NULL;  
  58. }  
  59.   
  60.   
  61. template<class TypeA,class TypeB,class FuncType>  
  62. HashMap<TypeA,TypeB,FuncType>::~HashMap(){  
  63.     for(unsigned i = 0;i < capacity;i++){  
  64.         HashNode<TypeA,TypeB> *currentNode = table[i];  
  65.         while(currentNode){  
  66.             HashNode<TypeA,TypeB> *temp = currentNode;  
  67.             currentNode = currentNode->next;  
  68.             delete temp;  
  69.         }  
  70.     }  
  71. }  
  72.   
  73.   
  74. //新增节点操作,用鏈式法解決衝突  
  75. template<class TypeA,class TypeB,class FuncType>  
  76. TypeB HashMap<TypeA,TypeB,FuncType>::Put(const HashNode<TypeA,TypeB>& hashNode){  
  77.     HashNode<TypeA,TypeB> *newNode = NULL;  
  78.     unsigned long index = GetKeyValue(hashNode.key);  
  79.     if(table[index] == NULL){  
  80.         table[index] = new HashNode<TypeA,TypeB>(hashNode.key,hashNode.value);  
  81.         newNode = table[index];  
  82.     }  
  83.     else{  
  84.         newNode = table[index];  
  85.         while(newNode->next){  
  86.             newNode = newNode->next;  
  87.         }  
  88.         newNode->next = new HashNode<TypeA,TypeB>(hashNode.key,hashNode.value);  
  89.         newNode = newNode->next;  
  90.     }  
  91.     return newNode->value;  
  92. }  
  93.   
  94.   
  95. //由键值获得value  
  96. template<class TypeA,class TypeB,class FuncType>  
  97. TypeB HashMap<TypeA,TypeB,FuncType>::GetValue(const TypeA& key){  
  98.     unsigned long index = GetKeyValue(key);  
  99.     if(table[index] == NULL)  
  100.         return TYPEB_NULL;  
  101.     else{  
  102.         HashNode<TypeA,TypeB> *currentNode = table[index];  
  103.         while(currentNode){  
  104.             if(currentNode->key == key)  
  105.                 return currentNode->value;  
  106.             currentNode = currentNode->next;  
  107.         }  
  108.     }  
  109.     return TYPEB_NULL;  
  110. }  
  111.   
  112.   
  113. //由键值查找后,删除该节点,返回该删除的节点的value  
  114. template<class TypeA,class TypeB,class FuncType>  
  115. TypeB HashMap<TypeA,TypeB,FuncType>::Delete(const TypeA& key){  
  116.     TypeB deletedNodeValue = TYPEB_NULL;  
  117.     unsigned long index = GetKeyValue(key);  
  118.     if(table[index] == NULL)  
  119.         return deletedNodeValue;  
  120.     else{  
  121.         HashNode<TypeA,TypeB> *currentNode = table[index];  
  122.         if(currentNode->key == key){  
  123.             table[index] = currentNode->next;  
  124.             deletedNodeValue = currentNode->value;  
  125.             delete currentNode;  
  126.             return deletedNodeValue;  
  127.         }  
  128.         while(currentNode){  
  129.             if(currentNode->next->key == key){  
  130.                 HashNode<TypeA,TypeB> *temp = currentNode->next;  
  131.                 currentNode->next = currentNode->next->next;  
  132.                 deletedNodeValue = temp->value;  
  133.                 delete temp;  
  134.                 return deletedNodeValue;;  
  135.             }  
  136.             currentNode = currentNode->next;  
  137.         }  
  138.     }  
  139.     return deletedNodeValue;  
  140. }  
  141.   
  142.   
  143.   
  144. /***************************************测试****************************/  
  145. //平方取中法  
  146. //实现,取字符串中间3个字母,不足3个用0补足  
  147. unsigned long GetKeyValue_1(const string& key){  
  148.     unsigned long keyValue = 0;  
  149.     int strSize = key.size();  
  150.     string tempStr(key);  
  151.     for(int i = strSize;i < 3;i++)  
  152.         tempStr = "0" + tempStr;  
  153.     //如果大于3就取中间3位  
  154.     if(strSize >= 3){  
  155.         tempStr[0] = key[strSize / 2 - 1];  
  156.         tempStr[1] = key[strSize / 2];  
  157.         tempStr[2] = key[strSize / 2 + 1];  
  158.     }  
  159.     tempStr = tempStr.substr(0,3);  
  160.     unsigned long num = 10000 * (unsigned long)(48);  
  161.     num += 100 * (unsigned long)(tempStr[1]);  
  162.     num += (unsigned long)(tempStr[2]);  
  163.     num *= num;  
  164.     char *numStr = new char[15];  
  165.     numStr = itoa(num,numStr,10) ;  
  166.     int strLen = strlen(numStr);  
  167.     tempStr = "000000";  
  168.     for(int i = -2;i < 4;i++)  
  169.         tempStr[2 + i] = numStr[strLen / 2 + i];  
  170.     keyValue = atoi(tempStr.c_str());  
  171.   
  172.     delete []numStr;  
  173.     return keyValue;  
  174. }  
  175.   
  176. int main(){  
  177.     clock_t start = clock();  
  178.     //传入一个求哈希散列值的方法GetKeyValue_1  
  179.     HashMap<string,string,GetKeyValue> hashMap(GetKeyValue_1,"NULL");  
  180.     for(int i = 0;i < 100000;i++){  
  181.         char *ckey = new char[20];  
  182.         char *cvalue = new char[20];  
  183.         ckey = itoa(i,ckey,10);  
  184.         cvalue = itoa(i,cvalue,10);  
  185.         string key(ckey);  
  186.         string value(cvalue);  
  187.         if(i == 67){  
  188.             key = "67";  
  189.             value = "hello hash No.67";  
  190.         }  
  191.         HashNode<string,string> node1(key,value);  
  192.         //插入该节点  
  193.         hashMap.Put(node1);  
  194. //        cout << "index: " <<GetKeyValue_1(key) << " nodeValue: "  
  195. //             << hashMap.Put(node1) << endl;  
  196.   
  197.     }  
  198.     clock_t end = clock();  
  199.     cout << "Test Result: \n";  
  200.     //调用了time.h文件的CLOCKS_PER_SEC,表示每过千分之一秒,clock()函数返回值加1  
  201.     cout << "插入100000条数据耗时: "  
  202.          << double(end - start) / CLOCKS_PER_SEC << " 秒" << endl;  
  203.     cout << "hashMap.GetValue(\"67\"): " << hashMap.GetValue("67") << endl;  
  204.     cout << "hashMap.Delete(\"67\"): " << hashMap.Delete("67") << endl;  
  205.     cout << "hashMap.GetValue(\"67\"): " << hashMap.GetValue("67") << endl;  
  206.     return 0;  
  207. }  




测试输出:

1) 函数测试

这里选用的是插入一万条的结果,测试函数是否正确。

每次新增、删除、搜索一个节点,就输出该节点的value值。

发现index为67的先加入后来成功删除,就输出了NULL


2) 性能测试:

插入10万条数据时间:

插入100万条:

插入1000万条:


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多