基本概念
哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
例如:给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。
散列表的关键在于:如何构造散列函数 和 如何处理冲突
概念在这就不详细解释了,可以参考:
这里只做简单的总结:
散列函数的构造方法
- 直接寻址法
- 数字分析法
- 平方取中法
- 折叠法
- 除留余数法
处理冲突的方法
- 开放地址法
- 链地址法
开发地址法的实现
#include <iostream>
#include <climits> // INT_MAX
#define NULL_KEY INT_MAX
using namespace std;
// 开地址法散列表存储结构
typedef struct
{
int *base; // 关键字
int size; // 散列表大小
}HashTable;
void Init(HashTable &HT, int size); // 初始化散列表
void destory(HashTable &HT); // 销毁散列表
int GetSize(HashTable &HT); // 获取散列表大小
int Hash(HashTable &HT, int key); // 散列函数
bool Insert(HashTable &HT, int key); // 插入
int Search(HashTable &HT, int key); // 查找
bool Remove(HashTable &HT, int key); // 删除
int main()
{
HashTable ht;
Init(ht, 100);
int key;
char ch;
while(cin >> ch >> key){
if(ch == 'i'){
cout << "insert " << key << (Insert(ht, key) ? " success!" : " failed!") << endl;
}
else if(ch == 'f'){
cout << (Search(ht, key) != GetSize(ht) ? "found it!" : "not found!") << endl;
}
else if(ch == 'd'){
cout << "remove " << key << (Remove(ht, key) ? " success!" : " failed!") << endl;
}
}
destory(ht);
return 0;
}
void Init(HashTable &HT, int size)
{
HT.base = new int[size];
HT.size = size;
for(int i = 0; i < size; ++ i){
HT.base[i] = NULL_KEY;
}
}
void destory(HashTable &HT)
{
delete HT.base;
HT.base = NULL;
HT.size = 0;
}
int GetSize(HashTable &HT)
{
return HT.size;
}
int Hash(HashTable &HT, int key)
{
return key % HT.size; /* 除留余数法 */
}
bool Insert(HashTable &HT, int key)
{
for(int i = 0; i <= HT.size; ++ i){
int pos = (Hash(HT, key) + i) % HT.size;
if(HT.base[pos] == NULL_KEY){
HT.base[pos] = key;
return true;
}
}
return false;
}
int Search(HashTable &HT, int key)
{
for(int i = 0; i <= HT.size; ++ i){
int pos = (Hash(HT, key) + i) % HT.size;
if(HT.base[pos] == key){
return pos;
}
else if(HT.base[pos] == NULL_KEY){
return HT.size;
}
}
return HT.size;
}
bool Remove(HashTable &HT, int key)
{
int pos = Search(HT, key);
if(pos != HT.size){
HT.base[pos] = NULL_KEY;
return true;
}
return false;
}
运行效果:
链地址法的实现
#include <iostream>
#include <cstring>
#include <climits> // INT_MAX
#define NULL_KEY INT_MAX
using namespace std;
// 链地址法散列表结点的存储结构
struct HashTableNode
{
int key;
HashTableNode *next;
};
// 链地址法散列表的存储结构
typedef struct
{
HashTableNode **head;
int size;
}HashTable;
void Init(HashTable &HT, int size); // 初始化散列表
void destory(HashTable &HT); // 销毁散列表
int GetSize(HashTable &HT); // 获取散列表大小
int Hash(HashTable &HT, int key); // 散列函数
bool Insert(HashTable &HT, int key); // 插入
int Search(HashTable &HT, int key); // 查找
bool Remove(HashTable &HT, int key); // 删除
int main()
{
HashTable ht;
Init(ht, 100);
int key;
char ch;
while(cin >> ch >> key){
if(ch == 'i'){
cout << "insert " << key << (Insert(ht, key) ? " success!" : " failed!") << endl;
}
else if(ch == 'f'){
cout << (Search(ht, key) != GetSize(ht) ? "found it!" : "not found!") << endl;
}
else if(ch == 'd'){
cout << "remove " << key << (Remove(ht, key) ? " success!" : " failed!") << endl;
}
}
destory(ht);
return 0;
}
void Init(HashTable &HT, int size)
{
HT.head = new HashTableNode*[size];
HT.size = size;
for(int i = 0; i < size; ++ i){
HT.head[i] = NULL;
}
}
void destory(HashTable &HT)
{
for(int i = 0; i < HT.size; ++ i){
HashTableNode *pNode = HT.head[i];
while(pNode){
HashTableNode *pNext = pNode->next;
delete pNode;
pNode = pNext;
}
}
delete HT.head;
HT.head = NULL;
HT.size = 0;
}
int GetSize(HashTable &HT)
{
return HT.size;
}
int Hash(HashTable &HT, int key)
{
return key % HT.size; /* 除留余数法 */
}
bool Insert(HashTable &HT, int key)
{
int pos = Hash(HT, key);
HashTableNode *pNode = new HashTableNode;
pNode->key = key;
pNode->next = HT.head[pos];
HT.head[pos] = pNode;
return true;
}
int Search(HashTable &HT, int key)
{
int pos = Hash(HT, key);
HashTableNode *pNode = HT.head[pos];
while(pNode){
if(pNode->key == key){
return pos;
}
pNode = pNode->next;
}
return HT.size;
}
bool Remove(HashTable &HT, int key)
{
int pos = Hash(HT, key);
HashTableNode *pNode = HT.head[pos], *pLast = NULL;
while(pNode){
if(pNode->key == key){
break;
}
pLast = pNode;
pNode = pNode->next;
}
if(pNode){
if(pLast){
pLast->next = pNode->next;
}
else{
HT.head[pos] = pNode->next;
}
delete pNode;
return true;
}
return false;
}
运行效果: