#ifndef _ROC_HASH_TABLE_H
#define _ROC_HASH_TABLE_H
#include <iostream>
#include <utility>
//Hash Table
//线形开址
template<typename KeyType, typename ValType>
class HashTable{
public:
typedef std::pair<KeyType, ValType> KeyValUnion; //键-值对
int m_nTableSize; //表大小
KeyValUnion *m_Table; //表中存储的值
int *m_UsedTable; //标记当前空间是否已使用
public:
//功能: 构造函数,初始化Hash表中元素值
HashTable():m_nTableSize(0), m_Table(NULL), m_UsedTable(NULL)
{}
//功能: 构造函数,生成一个大小为nSize的空哈希表
//参数:
// nSize: Hash表大小
HashTable(int nSize):m_nTableSize(0), m_Table(NULL), m_UsedTable(NULL)
{
//创建哈希表
CreateHashTable(nSize);
}
//功能:构造函数,用一个已存的Hash表初始化一个新表,表大小以及数据相同
//参数:
// hashTable: 已存Hash表
HashTable(const HashTable<KeyType, ValType> &hashTable)
{
m_nTableSize = 0;
m_Table = new KeyValUnion[hashTable.m_nTableSize];
if(NULL == m_Table)
return;
m_UsedTable = new int[hashTable.m_nTableSize];
if(NULL == m_UsedTable)
{
delete [] m_Table;
m_Table = NULL;
return;
}
m_nTableSize = hashTable.m_nTableSize;
memcpy(m_Table, hashTable.m_Table, sizeof(KeyValUnion)*m_nTableSize);
memcpy(m_UsedTable, hashTable.m_UsedTable, sizeof(int)*m_nTableSize);
}
//功能: 构造函数,用已存Hash表初始化一个大小为nSize的Hash表
//参数:
// nSize: Hash表大小;
// hashTable: 已存Hash表,用于提供数据
// lpfGetInt: 函数指针,用于将KeyType转为int值以计算在Hash表中的索引
HashTable(int nSize, const HashTable<KeyType, ValType> &hashTable, int (*lpfGetInt)(const KeyType&))
{
CreateHashTable(nSize, hashTable, lpfGetInt);
}
//功能: 析构函数
~HashTable()
{
Destroy();
}
//功能: 销毁当前Hash表
void Destroy()
{
m_nTableSize = 0;
if(m_Table)
{
delete [] m_Table;
m_Table = NULL;
}
if(m_UsedTable)
{
delete [] m_UsedTable;
m_UsedTable = NULL;
}
}
//功能: 创建大小为nSize的Hash表
//参数:
// nSize: Hash表大小
//返回值: 若创建成功则返回0, 否则失败返回-1
int CreateHashTable(int nSize)
{
if(nSize<1)
return -1;
KeyValUnion *valTable = new KeyValUnion[nSize];
if(NULL == valTable)
return -1;
int *usedTable = new int[nSize];
if(NULL == usedTable)
{
delete [] valTable;
valTable = NULL;
return -1;
}
//销毁Hash表中原有数据
Destroy();
m_Table = valTable;
m_UsedTable = usedTable;
m_nTableSize = nSize;
memset(m_Table, 0, sizeof(KeyValUnion)*nSize);
memset(m_UsedTable, 0, sizeof(int)*nSize);
return 0;
}
//功能: 创建一个大小为nSize的Hash表,并的HashTable
//参数:
// nSize: Hash表大小;
// hashTable: 已存Hash表,用于提供数据
// lpfGetInt: 函数指针,用于将KeyType转为int值以计算在Hash表中的索引
//返回值:若创建成功则返回0,否则返回-1
int CreateHashTable(int nSize, const HashTable<KeyType, ValType> &hashTable, int (*lpfGetInt)(const KeyType&))
{
if(nSize<1)
return -1;
if(&hashTable == this)
return -1;
if(CreateHashTable(nSize)!=0)
return -1;
int result;
for(int i=0; i<hashTable.m_nTableSize; i++)
{
//若hashTable的当前空间已存储数据,则插入到新Hash表中
if(hashTable.m_UsedTable[i]!=0)
{
result = Insert(hashTable.m_Table[i].first, hashTable.m_Table[i].second, lpfGetInt);
if(result != 0)
return -1; //当前表已满,插入失败,之前插入的元素已复制到当前表中
}
}
return 0;
}
//功能: 查找键值为key的数据, 并获取该键值对应的数据
//参数:
// key: 用于查找数据的键值
// outVal[out]: 输出值, 该键值对应的数据
// lpfGetInt: 函数指针,用于将KeyType转为int值以计算在Hash表中的索引
//返回值: 查找成功则返回0, 否则返回-1
int Search(const KeyType &key, ValType &outVal, int(*lpfGetInt)(const KeyType&))
{
//计算索引值
int idx = lpfGetInt(key)%m_nTableSize;
//若当前空间未使用,查找失败
if(0==m_UsedTable[idx])
return -1;
int curIdx = idx;
do{
//检查当前项键值是否正确
if(m_Table[curIdx].first == key) //用户需要为KeyType重载“==”运算符
{
outVal = m_Table[curIdx].second; //用户需要为ValType重载“=”运算符
return 0; //查找成功
}
++curIdx;
curIdx = curIdx % m_nTableSize;
}while(m_UsedTable[curIdx]!=0 && curIdx != idx);
return -1; //查找失败
}
//功能:向Hash表插入数据
//参数:
// key: 用于计算索引的键值
// val: 插入值, 该键值对应的数据
// lpfGetInt: 函数指针,用于将KeyType转为int值以计算在Hash表中的索引
//返回值: 插入数据成功则返回0, 否则返回-1
int Insert(const KeyType &key, const ValType &val, int(*lpfGetInt)(const KeyType&))
{
//起始索引
int idx = lpfGetInt(key)%m_nTableSize;
//碰撞处理 线型寻址散列
int curIdx = idx;
do{
//若线形开址找到空闲空间则插入元素
if(0 == m_UsedTable[curIdx])
{
m_UsedTable[curIdx] = 1; //标为已用
m_Table[curIdx].first = key; //用户需要为KeyType重载“=”运算符
m_Table[curIdx].second = val; //用户需要为ValType重载“=”运算符
return 0;
}
curIdx = (curIdx+1)%m_nTableSize;
}while(curIdx != idx);
return -1;
}
//功能: 打印Hash表中元素
void Print()
{
for(int i=0; i<m_nTableSize; i++)
std::cout<<"Index: "<<i<<", Used: "<<(m_UsedTable[i]?"True":"False")<<", Key: "
<<m_Table[i].first<<", Val: "<<m_Table[i].second<<std::endl;
}
};
#endif //#ifndef _ROC_HASH_TABLE_H
//-----------------------------------------------------------------------------------------------------------
//test.Cpp
#include "stdafx.h"
#include "string.h"
#include "HashTable.h"
int GetInt(const double& val)
{
return int(val+0.5);
}
struct ValType{
char name[8];
int id;
public:
ValType& operator=(const ValType &val)
{
id = val.id;
memcpy(name, val.name, sizeof(char)*8);
return *this;
}
friend std::ostream& operator<<(std::ostream &out, const ValType &val);
};
std::ostream& operator<<(std::ostream &out, const ValType &val)
{
out<<"ID = "<<val.id<<", Name = "<<val.name;
return out;
}
int _tmain(int argc, _TCHAR* argv[])
{
int result;
HashTable<double, ValType> hashTable(11);
ValType val;
val.id = 1;
strcpy(val.name, "a");
result = hashTable.Insert(80.5, val, GetInt); //1 a
val.id++;
val.name[0]++;
result = hashTable.Insert(40.2, val, GetInt); //2 b
val.id++;
val.name[0]++;
result = hashTable.Insert(65.5, val, GetInt); //3 c
val.id++;
val.name[0]++;
result = hashTable.Insert(24.3, val, GetInt); //4 d
val.id++;
val.name[0]++;
result = hashTable.Insert(58.2, val, GetInt); //5 e
val.id++;
val.name[0]++;
result = hashTable.Insert(35.6, val, GetInt); //6 f
hashTable.Print();
std::cout<<std::endl<<std::endl;
ValType a6;
result = hashTable.Search(35, a6, GetInt);
result = hashTable.Search(58.2, a6, GetInt);
HashTable<double, ValType> hashTable2;
hashTable2.CreateHashTable(8, hashTable, GetInt);
hashTable2.Print();
return 0;
}
注意:
1.该Hash Table处理碰撞时使用线型寻址散列。
2.用户需要为KeyType重载“=”和“== ”运算符
3.用户需要为ValType重载“=”运算符