目录
背景
常用哈希函数
除留取余法
设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数,按照哈希
函数:H a s h ( K e y ) = K e y % p ( p < = m ) ,将关键码转换成哈希地址。
优点:使用场景广泛,不受限制。
缺点:存在哈希冲突,需要解决哈希冲突,哈希冲突越多,效率下降越厉害。
解决冲突的方法:
闭散列:也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表种必然还有空位置,那么可以把产生冲突的元素存放到冲突位置的“下一个”空位置中去
当前位置被占用,开放空间里按照某种规则找一个没有被占用的位置存储
1.线性探测法:hashi+i (i>=0)
2.二次探测法:hashi+i^2 (i>=0)
实现
我们这里实现主要采用线性探测法
设置状态
存储
这里我们定义结构体来保存该位置的数据和状态,设置一个存储该结构体的·vector来实现,并用n
来保存有效元素的个数
获取key函数
这里我们需要用key来%数组的size来获取该元素的位置,如果是int类型我们可以%,但如果是string类型我们就不能直接取模
构造函数
插入
查找
删除
打印
完整代码
#pragma once
namespace Hash_Close
{
enum status
{
EMPTY, //空
EXIST, //存在
DELETE //删除
};
template<class K,class V>
struct HashData
{
pair<K, V> _kv;
status _s;
};
template<class K>
struct HashFunc
{
size_t operator()(const K& key)
{
return size_t(key);
}
};
template<> //类模板调用优先级:全特化类 > 偏特化类 > 主版本模板类
struct HashFunc<string>
{
size_t operator()(const string& s)
{
size_t hash = 0;
for (auto e : s)
{
hash *= 13;
hash += e;
}
return hash;
}
};
template<class K, class V, class Hash = HashFunc<K>>
class HashTable
{
public:
HashTable()
{
_tables.resize(10);
_n = 0;
}
bool Insert(const pair<K,V>& kv)
{
if (Find(kv.first))
{
return false;
}
//负载 0.7
if (_n * 10 / _tables.size() == 7)
{
//扩容
size_t newsize = _tables.size() * 2;
HashTable<K, V,Hash> NewHT;
NewHT._tables.resize(newsize);
for (size_t i = 0; i < _tables.size(); i++)
{
if(_tables[i]._s==EXIST)
NewHT.Insert(_tables[i]._kv);
}
_tables.swap(NewHT._tables);
}
Hash hf;
size_t hashi = hf(kv.first) % _tables.size();
while (_tables[hashi]._s == EXIST)
{
hashi++;
hashi %= _tables.size();
}
_tables[hashi]._kv = kv;
_tables[hashi]._s = EXIST;
_n++;
return true;
}
HashData<K, V>* Find(const K& key)
{
Hash hf;
size_t hashi = hf(key) % _tables.size();
while (_tables[hashi]._s != EMPTY)
{
if (_tables[hashi]._s == EXIST
&& _tables[hashi]._kv.first == key)
{
return &_tables[hashi];
}
hashi++;
hashi %= _tables.size();
}
return NULL;
}
bool Erase(const K& key)
{
HashData<K, V>* ret = Find(key);
if (ret)
{
ret->_s = DELETE;
_n--;
return true;
}
else
{
return false;
}
}
void Print()
{
for (size_t i = 0; i < _tables.size(); i++)
{
if (_tables[i]._s == EXIST)
{
cout << '[' << i << "]->" << _tables[i]._kv.first << ":" << _tables[i]._kv.second << endl;
}
else if (_tables[i]._s == EMPTY)
{
printf("[%d]->\n", i);
}
else
{
printf("[%d]->D\n", i);
}
}
cout << endl;
}
private:
vector<HashData<K, V>> _tables;
size_t _n; //存储有效元素的个数
};
void test1()
{
HashTable<int, int> ht;
int a[] = { 4,14,24,34,5,7,1 };
for (auto e : a)
{
ht.Insert(make_pair(e, e));
}
ht.Insert(make_pair(3, 3));
ht.Insert(make_pair(3, 3));
ht.Insert(make_pair(-3, -3));
ht.Print();
ht.Erase(3);
ht.Print();
if (ht.Find(3))
{
cout << "3存在" << endl;
}
else
{
cout << "3不存在" << endl;
}
ht.Insert(make_pair(3, 3));
ht.Insert(make_pair(23, 3));
ht.Print();
}
void test2()
{
string arr[] = { "香蕉", "甜瓜","苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
//HashTable<string, int, HashFuncString> ht;
HashTable<string, int> ht;
for (auto& e : arr)
{
//auto ret = ht.Find(e);
HashData<string, int>* ret = ht.Find(e);
if (ret)
{
ret->_kv.second++;
}
else
{
ht.Insert(make_pair(e, 1));
}
}
ht.Print();
ht.Insert(make_pair("apple", 1));
ht.Insert(make_pair("sort", 1));
ht.Insert(make_pair("abc", 1));
ht.Insert(make_pair("acb", 1));
ht.Insert(make_pair("aad", 1));
ht.Print();
}
}