散列表(哈希表)及其实现

基本概念

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

运行效果:
这里写图片描述


展开阅读全文
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值