HashTable(不使用链表的散列表)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013021513/article/details/42397459

分离链接散列算法的缺点是使用一些链表,由于给新单元分配地址需要时间,因此这就导致算法的速度有些缓慢,同时算法实际上还需要第二种数据结构的实现。下面就用探测散列表来实现哈希表。

1.线性探测

在线性探测中,函数f是i的线性函数,一般情况下f(i) = i,这相当于逐个探测每个单元(使用回绕)来查找出空单元。

2.平方探测

平方探测是消除线性探测中一次聚集问题的冲突解决方法。平方探测就是冲突函数为二次函数的探测方法。流行的选择时f(i) = i²,对于线性探测,让散列表近乎填满元素是个坏主意,因为此时表的性能会降低。对于平方探测,情况甚至更糟:一旦表被填满超过一半,若表的大小不是素数,那么甚至在表被填满一半之前,就不能保证找到空的元素了,这是因为最多只有表的一半可以用做解决冲突的备选位置。

下面为探测散列表的代码:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
template<typename HashedObj>
class HashTable
{
public:
    explicit HashTable(int size = 101) : array(size)
    {
        makeEmpty();
        currentSize = size;
    }
    bool contains(const HashedObj & x) const;
    void makeEmpty();
    bool insert(const HashedObj & x);
    bool remove(const HashedObj & x);
    enum EntryType {ACTIVE,EMPTY,DELETED};
private:
    struct HashEntry
    {
        HashedObj element;
        EntryType info; //状态,惰性删除用

        HashEntry(const HashedObj & e = HashedObj(),EntryType i = EMPTY) :element(e),info(i) {}
    };
    vector<HashEntry> array;
    int currentSize;
    bool isActive(int currentPos) const;
    int findPos(const HashedObj & x) const;
    void rehash();
    int myhash(const HashedObj & x) const;
};
bool Prime(int res)
{
    for(int i=2;i<res/2;i++)
    {
        if(res % i == 0)
        {
            return true;
            break;
        }
    }
    return false;
}
int nextPrime(int num)
{
    while(1)
    {
        if(Prime(num) == false)
        {
            return num;
            break;
        }
        else
        {
            num++;
        }
    }
}
int hash(const string &key)
{
    int hashVal = 0;

    for(int i = 0; i < key.length(); i++)
    {
        hashVal = hashVal * 37 + key[i];
    }

    return hashVal;
}
int hash(int key)
{
    return key;
}
template<typename HashedObj>
int HashTable<HashedObj>::myhash(const HashedObj & x) const
{
    int hashVal = hash(x);
    hashVal %= array.size();  //theLists.size()为总容量
    if(hashVal < 0)
    {
        hashVal += array.size();
    }
    return hashVal;
}
template<typename HashedObj>
void HashTable<HashedObj>::makeEmpty()
{
    currentSize = 0;
    for(int i=0;i<array.size();i++)
    {
        array[i].info = EMPTY;
    }
}
template<typename HashedObj>
bool HashTable<HashedObj>::contains(const HashedObj & x) const
{
    return isActive(findPos(x));
}
template<typename HashedObj>
int HashTable<HashedObj>::findPos(const HashedObj & x) const
{
    int offset = 1;
    int currentPos = myhash(x);
    /*
    如果该位置已存在元素,或者插入的值为没有出现过的值,以下为平方探测的方法 递推式为f(n) = f(n-1) + 2n - 1
    */
    while(array[currentPos].info != EMPTY && array[currentPos].element != x) //本行的两个条件顺序很重要,切勿交换
    {
        currentPos += offset; //Compute ith probe
        offset += 2;
        if(currentPos >= array.size())
        {
            currentPos -= array.size(); // 防止超过
        }
    }
    return currentPos;
}
template<typename HashedObj>
void HashTable<HashedObj>::rehash()
{
    vector<HashEntry> oldArray = array;
    //建立两倍的空间
    array.resize(nextPrime((2*oldArray.size())));
    //cout<<array.size()<<endl;
    for(int j=0;j<array.size();j++)
    {
        array[j].info = EMPTY;
    }
    currentSize = 0;
    for(int i=0;i<oldArray.size();i++)
    {
        if(oldArray[i].info == ACTIVE) // 前面的数据赋值给新的空间
            insert(oldArray[i].element);
    }
}
template<typename HashedObj>
bool HashTable<HashedObj>::isActive(int currentPos) const
{
    return array[currentPos].info == ACTIVE; //判断是否存在或者不存在
}
template<typename HashedObj>
bool HashTable<HashedObj>::insert(const HashedObj & x)
{
    int currentPos = findPos(x);
    if(isActive(currentPos)) //表示已经存在
    {
        return false;
    }
    array[currentPos] = HashEntry(x,ACTIVE); //HashEntry的数组对象,每个数组元素都有它的元素和info
    if(++currentSize > array.size() / 2) //如果数据量已经超过一半了,那就要当前空间要扩容2倍
        rehash();
    return true;
}
template<typename HashedObj>
bool HashTable<HashedObj>::remove(const HashedObj & x)
{
    int currentPos = findPos(x);
    if(!isActive(currentPos)) //如果不存在
    {
        return false;
    }
    array[currentPos].info = DELETED;
    return true;
}
int main()
{
    HashTable<int> b;
    b.insert(1);
    b.insert(10);
    b.insert(100);
    b.insert(9);
    b.insert(69);
    b.insert(57);
    if(b.contains(100) && b.contains(57))
    {
        cout<<"yes"<<endl;
    }
    else
    {
        cout<<"no"<<endl;
    }
    if(b.insert(57))
    {
        cout<<"insert succeed!"<<endl;
    }
    else
    {
        cout<<"repeat!"<<endl;
    }
    if(b.remove(69))
    {
        cout<<"remove succeed!"<<endl;
    }
    else
    {
        cout<<"The element not exist in HashTable";
    }
    b.makeEmpty();
    if(b.contains(1) || b.contains(10) || b.contains(100))
    {
        cout<<"The HashTable is not empty!"<<endl;
    }
    else
    {
        cout<<"It is empty!"<<endl;
    }
    return 0;
}


阅读更多
换一批

没有更多推荐了,返回首页