简述:
考虑到有大量数据的情况,所以使用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
-
-
-
-
- #include <iostream>
- #include <string>
- #include <cstring>
- #include <stdlib.h>
- #include <time.h>
-
- using namespace std;
-
- typedef unsigned long(*GetKeyValue)(const string& );
-
-
- template<class TypeA,class TypeB>
- struct HashNode{
- TypeA key;
- TypeB value;
- HashNode *next;
- HashNode(TypeA key,TypeB value){
- HashNode::key = key;
- HashNode::value = value;
- next = NULL;
- }
- HashNode& operator=(const HashNode& node){
- key = node.key;
- value = node.key;
- next = node.next;
- return *this;
- }
- };
-
-
-
- template<class TypeA,class TypeB,class FuncType>
- class HashMap{
- HashNode<TypeA,TypeB> **table;
- unsigned long capacity;
- FuncType GetKeyValue;
- const TypeB TYPEB_NULL;
- public:
- HashMap(FuncType func,const TypeB& _null);
- ~HashMap();
- TypeB Put(const HashNode<TypeA,TypeB>& hashNode);
- TypeB GetValue(const TypeA& key);
- TypeB Delete(const TypeA& key);
- };
-
-
- template<class TypeA,class TypeB,class FuncType>
- HashMap<TypeA,TypeB,FuncType>::HashMap(FuncType func,const TypeB& _null) : TYPEB_NULL(_null){
- capacity = 10000000;
- GetKeyValue = func;
- table = new HashNode<TypeA,TypeB>*[capacity];
- for(unsigned i = 0;i < capacity;i++)
- table[i] = NULL;
- }
-
-
- template<class TypeA,class TypeB,class FuncType>
- HashMap<TypeA,TypeB,FuncType>::~HashMap(){
- for(unsigned i = 0;i < capacity;i++){
- HashNode<TypeA,TypeB> *currentNode = table[i];
- while(currentNode){
- HashNode<TypeA,TypeB> *temp = currentNode;
- currentNode = currentNode->next;
- delete temp;
- }
- }
- }
-
-
-
- template<class TypeA,class TypeB,class FuncType>
- TypeB HashMap<TypeA,TypeB,FuncType>::Put(const HashNode<TypeA,TypeB>& hashNode){
- HashNode<TypeA,TypeB> *newNode = NULL;
- unsigned long index = GetKeyValue(hashNode.key);
- if(table[index] == NULL){
- table[index] = new HashNode<TypeA,TypeB>(hashNode.key,hashNode.value);
- newNode = table[index];
- }
- else{
- newNode = table[index];
- while(newNode->next){
- newNode = newNode->next;
- }
- newNode->next = new HashNode<TypeA,TypeB>(hashNode.key,hashNode.value);
- newNode = newNode->next;
- }
- return newNode->value;
- }
-
-
-
- template<class TypeA,class TypeB,class FuncType>
- TypeB HashMap<TypeA,TypeB,FuncType>::GetValue(const TypeA& key){
- unsigned long index = GetKeyValue(key);
- if(table[index] == NULL)
- return TYPEB_NULL;
- else{
- HashNode<TypeA,TypeB> *currentNode = table[index];
- while(currentNode){
- if(currentNode->key == key)
- return currentNode->value;
- currentNode = currentNode->next;
- }
- }
- return TYPEB_NULL;
- }
-
-
-
- template<class TypeA,class TypeB,class FuncType>
- TypeB HashMap<TypeA,TypeB,FuncType>::Delete(const TypeA& key){
- TypeB deletedNodeValue = TYPEB_NULL;
- unsigned long index = GetKeyValue(key);
- if(table[index] == NULL)
- return deletedNodeValue;
- else{
- HashNode<TypeA,TypeB> *currentNode = table[index];
- if(currentNode->key == key){
- table[index] = currentNode->next;
- deletedNodeValue = currentNode->value;
- delete currentNode;
- return deletedNodeValue;
- }
- while(currentNode){
- if(currentNode->next->key == key){
- HashNode<TypeA,TypeB> *temp = currentNode->next;
- currentNode->next = currentNode->next->next;
- deletedNodeValue = temp->value;
- delete temp;
- return deletedNodeValue;;
- }
- currentNode = currentNode->next;
- }
- }
- return deletedNodeValue;
- }
-
-
-
-
-
-
- unsigned long GetKeyValue_1(const string& key){
- unsigned long keyValue = 0;
- int strSize = key.size();
- string tempStr(key);
- for(int i = strSize;i < 3;i++)
- tempStr = "0" + tempStr;
-
- if(strSize >= 3){
- tempStr[0] = key[strSize / 2 - 1];
- tempStr[1] = key[strSize / 2];
- tempStr[2] = key[strSize / 2 + 1];
- }
- tempStr = tempStr.substr(0,3);
- unsigned long num = 10000 * (unsigned long)(48);
- num += 100 * (unsigned long)(tempStr[1]);
- num += (unsigned long)(tempStr[2]);
- num *= num;
- char *numStr = new char[15];
- numStr = itoa(num,numStr,10) ;
- int strLen = strlen(numStr);
- tempStr = "000000";
- for(int i = -2;i < 4;i++)
- tempStr[2 + i] = numStr[strLen / 2 + i];
- keyValue = atoi(tempStr.c_str());
-
- delete []numStr;
- return keyValue;
- }
-
- int main(){
- clock_t start = clock();
-
- HashMap<string,string,GetKeyValue> hashMap(GetKeyValue_1,"NULL");
- for(int i = 0;i < 100000;i++){
- char *ckey = new char[20];
- char *cvalue = new char[20];
- ckey = itoa(i,ckey,10);
- cvalue = itoa(i,cvalue,10);
- string key(ckey);
- string value(cvalue);
- if(i == 67){
- key = "67";
- value = "hello hash No.67";
- }
- HashNode<string,string> node1(key,value);
-
- hashMap.Put(node1);
-
-
-
- }
- clock_t end = clock();
- cout << "Test Result: \n";
-
- cout << "插入100000条数据耗时: "
- << double(end - start) / CLOCKS_PER_SEC << " 秒" << endl;
- cout << "hashMap.GetValue(\"67\"): " << hashMap.GetValue("67") << endl;
- cout << "hashMap.Delete(\"67\"): " << hashMap.Delete("67") << endl;
- cout << "hashMap.GetValue(\"67\"): " << hashMap.GetValue("67") << endl;
- return 0;
- }
测试输出:
1) 函数测试
这里选用的是插入一万条的结果,测试函数是否正确。
每次新增、删除、搜索一个节点,就输出该节点的value值。
发现index为67的先加入后来成功删除,就输出了NULL

2) 性能测试:
插入10万条数据时间:

插入100万条:

插入1000万条:
