基本概念
哈希表(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;
}
運行效果: