简单哈希表学习

原文地址:https://blog.csdn.net/Hu_weichen/article/details/80820728

自己输入跑了一下:

#include <vector>
#define NULLKEY - 32768

class HashTable
{
public:
    HashTable(int n);
    ~HashTable();
    void InsertHash(int key);
    int searchHash(int key);
    void show();
private:
    int hash(int key);
    vector<int> elem;
    int count;
    int m;
};

HashTable::HashTable(int n):count(0),m(n)
{
    for(int i =0 ;i <n;++i)
    {
        elem.push_back(NULLKEY);
    }
}

HashTable::~HashTable()
{}

int HashTable::hash(int key)
{
    return key % m;
}

void HashTable::InsertHash(int key)
{
    int addr = hash(key);
    while(NULLKEY != elem[addr])
    {
        addr = (addr+1)%m;
    }
    elem[addr] = key;
    count++;
}

int HashTable::searchHash(int key)
{
    int addr = hash(key);
    while(elem[addr] != key)
    {
        addr = (addr +1)%m;
        if(NULLKEY == elem[addr] || hash(key) == addr)
        {
            return -1;
        }
    }
    return addr;
}

void HashTable::show()
{
    for(int i = 0;i < m;i++)
    {
        cout << elem[i]<<endl;
    }
}

int main()
{
    int n,e,val;
    vector<int> vec;
    cout << "输入元素个数:";
    cin >> n;
    cout << "输入数据元素:"<<endl;
    for(int i = 0; i < n ;i++)
    {
        cin >>e;
        vec.push_back(e);
    }
    HashTable H(n);
    for(int i =0;i<n;++i)
    {
        H.InsertHash(vec[i]);
    }
    cout<<"散列表"<<endl;
    H.show();
    while(1)
    {
        cout<<"输入要查找的数据元素:";
        cin>>val;
        e= H.searchHash(val);
        if(-1 == e)
        {
            break;
            cout<<"look up failed!"<<endl;
        }
        else
        {
            cout<<"下标为:"<<e<<endl;
        }
    }
    system("pause");
}

以上是原文代码,主要说下自己输入的一点理解。

代码首先是构造了一个长度固定的vector来存储key值,当然这个固定的长度n也是手动输入的

散列函数用的是除留余数法

int HashTable::hash(int key)
{
    return key % m;
}

主要是为了收敛key对应的地址,f(key)的值在0~m-1之间

插值函数:

void HashTable::InsertHash(int key)
{
    int addr = hash(key);
    while(NULLKEY != elem[addr])
    {
        addr = (addr+1)%m;
    }
    elem[addr] = key;
    count++;
}

得到key的哈希地址addr之后,如果elem[addr]尚未被填充数据,则elem[addr] = key,否则addr加上一个偏移量继续直到找到未被填充数据的elem[addr], 原文这里addr = (addr+1)%key显然不对,因为地址显然在0~(m-1)之间移动,已修正

查找函数:

int HashTable::searchHash(int key)
{
    int addr = hash(key);
    while(elem[addr] != key)
    {
        addr = (addr +1)%m;
        if(NULLKEY == elem[addr] || hash(key) == addr)
        {
            return -1;
        }
    }
    return addr;
}

这个函数是整个里面唯一不太好理解的,这个要结合插值函数看,首先如果这个查询的key值存在对应的地址对应,那么在不断的偏移判断elem[addr] 是否为key的循环中,定然能找到elem[addr] = key的addr值,所以第一次情况如果NULLKEY == elem[addr] 了都没有将key值插入这个存储数组中,那显然这个key并没有对应的地址,这种情况存储的key地址对是小于m的,所以存在未填充key的地方,所以还存在第二种情形,key地址对与m,n是相等的,elem[]数组被填充满,addr+1地址从0~m-1遍历了一遍任未找到elem[addr] = key,然后又回到了0(假设从第一次哈希运算得到0),这时使得hash(key) == addr又重新成立,此种情形也能说明哈希表中不存在这个key值。

原文地址:https://www.cnblogs.com/doulcl/p/10907517.html