哈希表是常见数据结构中一种拥有高效插入,高效查找的结构,时间复杂度为O(1)。
闭散列哈希的不足之处就是随着冲突的数据增多,插入的效率也会随之变慢,为了优化闭散列哈希的效率,我们可以采取以下的方式:
>1.当插入的数据占总大小的一定比率的时候,也称负载因子,我们可以对哈希表进行扩容,重新通过哈希函数求得位置插入。
>2.我们可以采用素数表的形式,来减少哈希冲突的可能。
>3.通过更好优化的哈希函数,来减少冲突的可能。
每次扩容,带来的也是巨大的开销,首先要开辟新的空间,其次,重新插入需要通过哈希函数重新求得新插入的位置。
1。我们通过对每个哈希节点进行标记,三种标记分别为EMPTY空白,DELETE删除,EXIST存在。分别表示此处没有插入过数据,插入过数据但当前位置数据已经删除,此处存在数据。
2。当我们进行查找的时候,如果前k值通过哈希函数求得位置向后查找,如果为EMPTY则停下,当找到表的尾部,然后从0开始继续查找。
3。当我们插入的时候,同理求得插入位置,如果该位置已经有值,我们向后查找,当遇到EMPTY或者DELETE时,该位置没有数据,在该位置插入。
我们在插入时,通过函数CheckLoadFactor()来检测当前负载因子,当负载因子当到我们设定的比率时,我们采用对哈希表进行扩,扩容的大小为每次素数表中的下一个素数大小。
本次哈希表中的哈希函数,使用的是直接定值法。
#include<iostream>
#include<vector>
using namespace std;
enum condition
{
EMPTY,
DELETE,
EXIST,
};
template<class K, class V>
struct Hashnode
{
K key;
V value;
condition con;
Hashnode(const K k = K(), const V v = V())
:key(k)
, value(v)
, con(EMPTY)
{}
};
template<class K>
struct HashFun
{
size_t operator()(K k)
{
return k;
}
};
template<class K, class V, class __HashFun = HashFun<K> >
class Hashtable
{
public:
typedef Hashnode<K, V> node;
Hashtable()
:size(0)
{}
Hashtable(const Hashtable& h)
:size(0)
{
for (size_t index = 0; index<h.table.size(); index++)
{
Insert(h.table[index].key, h.table[index].value);
}
}
Hashtable& operator=(Hashtable h)
{
table.swap(h.table);
swap(size, h.size);
return *this;
}
bool Insert(K k, V v)
{
CheckLoadFactor();
size_t index = Hashfun(k);
while (table[index].key = k || (table[index].key = k&&table[index].con != EXIST))
{
if (table[index].con != EXIST)
{
table[index].key = k;
table[index].value = v;
table[index].con = EXIST;
size++;
return true;
}
index++;
if (index>table.size())
{
index = 0;
}
}
return false;
}
size_t Hashfun(const K& k)
{
__HashFun hashfun;
return hashfun(k) % table.size();
}
node* Find(const K& k)
{
size_t index = Hashfun(k);
while (table[index].con != EMPTY)
{
if (table[index].key == k&&table[index].con == EXIST)
{
return &table[index];
}
index++;
if (index>table.size())
{
index = 0;
}
}
return NULL;
}
bool Erase(const K& pos)
{
if (Find(pos) != NULL)
{
Find(pos)->con = DELETE;
size--;
return true;
}
return false;
}
private:
void CheckLoadFactor()
{
if (table.size() == 0 || (size * 10 / table.size())>7)
{
table.size() == 0 ? table.resize(7) : Changecapacity();
}
}
void Changecapacity()
{
Hashtable<K, V, __HashFun> newtable;
newtable.table.resize(GetNextPrime(table.size()));
for (size_t index = 0; index<table.size(); index++)
{
if (table[index].con == EXIST)
{
newtable.Insert(table[index].key, table[index].value);
}
}
table.swap(newtable.table);
}
size_t GetNextPrime(size_t pre)
{
const size_t _PrimeSize = 28;
static const unsigned long _PrimeList[_PrimeSize] =
{
53ul, 97ul, 193ul, 389ul, 769ul,
1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
1610612741ul, 3221225473ul, 4294967291ul
};
for (size_t index = 0; index<_PrimeSize; index++)
{
if (pre<_PrimeList[index])
return _PrimeList[index];
}
return _PrimeList[_PrimeSize - 1];
}
private:
vector<node> table;
size_t size;
};