散列表(哈希表)及其實現

基本概念

哈希表(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;
}

運行效果:
這裏寫圖片描述


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章