线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。
负载因子:存放数据的个数,和数组的长度的比值;比值越低,说明冲突的可能性越小…应严格限制在0.7左右…
二次探测:找下一个空位置的方法进行了改进,让有相同哈希地址的分散一点,不要太集中。
闭散列最大的缺陷就是空间利用率比较低,这也是哈希的缺陷。
ntspt = start+i*2;
namespace close_hash
{
enum status
{
EMPTY,
EXIST,
DEL
};
template<class K,class V>
struct hash_data
{
pair<K,V> _data;
status _st = EMPTY;
};
---
template<class K, class V>
class hash_table
{
typedef hash_data<K, V> hashdata;
public:
....
private:
vector<hashdata> _ht;
size_t _n= 0;//有效数据的个数
};
}
bool Insert(const pair<K, V>& kv)
{
if (find(kv.first))//先看K值在不在数组里
{
return false;
}
if (_n==_ht.size() || _n*10 /_ht.size()>=7) //看是不是空的或者负载因子大于7 越大,说明越冲突
{
size_t newsize = _ht.size() == 0 ? 10 : _ht.size() * 2;
hash_table<K,V> newht;
newht._ht.resize(newsize);
for (auto& i : _ht)
{
if (i._st == EXIST)//把是存在状态的数据插入到新数组里。
{
newht.Insert(i._data);
}
}
_ht.swap(newht._ht);
}
size_t start = kv.first % _ht.size(); //数组的下标
size_t i = 0;
size_t inspt = start + i;//冲突了往后找空位置
while (_ht[inspt]._st == EXIST)
{
++i;
inspt = start + i;
//intspt = start+i*2;
inspt %= _ht.size();
}
_ht[inspt]._data = kv;
_ht[inspt]._st = EXIST;
_n++;
return true;
}
hashdata* find(const K& key)
{
if (_n==0)
{
return nullptr;
}
size_t findk = key%_ht.size();//找坐标
while (_ht[findk]._st != EMPTY)
{
if (_ht[findk]._st == EXIST && _ht[findk]._data.first == key)
{
return &_ht[findk];
}
++findk;//往后找
}
return nullptr;
}
bool Erase(const K& key)
{
if (_n==0)
{
return true;
}
auto ret = find(key);
if (ret)
{
ret->_st = DEL;//伪删除..
_n++;
return true;
}
return false;
}
void test()
{
close_hash::hash_table<int, int> ht1;
ht1.Insert(make_pair(10, 20));
ht1.Insert(make_pair(30, 20));
ht1.Insert(make_pair(24, 20));
ht1.Insert(make_pair(34, 20));
ht1.Insert(make_pair(44, 20));
ht1.Insert(make_pair(54, 20));
ht1.Insert(make_pair(64, 20));
ht1.Insert(make_pair(74, 20));
ht1.Erase(74);
}
namespace myhash
{
template<class T>
struct HashData
{
HashData<T>* _next;
T _data;
HashData(const T& kv)
:_next(nullptr)
,_data(kv)
{
}
};
//每次数组满了进行扩容的长度建议.
size_t GetNextPrime(size_t prime)
{
const int PRIMECOUNT = 28;
static const size_t primeList[PRIMECOUNT] =
{
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
};
size_t i = 0;
for (; i < PRIMECOUNT; ++i)
{
if (primeList[i] > prime)//传过来原数组的长度
return primeList[i];
}
return primeList[i];
}
.....
template<class K, class T,class HashFunc= HashFunc<K>, class KeyofT= KeyofT<K,T>>
class HashTable
{
friend Hashiterator<K, T, HashFunc, KeyofT>; //友元
typedef HashData<T> Node; //单个数据类型
typedef Hashiterator<K, T, HashFunc, KeyofT> iterator; //迭代器
public:
..
private:
vector<Node*> _tabarry;
size_t _n = 0;//存储的有效数据
};
~HashTable()
{
for (size_t i = 0; i < _tabarry.size(); i++)
{
Node* cur = _tabarry[i];
while (cur)
{
Node* next = cur->_next;
delete cur;
cur = next;
}
_tabarry[i] = nullptr;
}
_n;
cout << "最后还是调用我了呵呵呵" << endl;
}
template<class K,class T>
struct KeyofT
{
const K& operator()(const T& kv)
{
return kv.first;
}
};
template<class K>
struct HashFunc
{
size_t operator()(const K& key) //float double 等等支持隐式类型转换的都可以
{
return key;
}
};
template<>//特化
struct HashFunc<string>
{
size_t operator()(const string& key)
{
// BKDR Hash思想 把字符串的每个字符乘上131.
size_t hash = 0;
for (size_t i = 0; i < key.size(); i++)
{
hash *= 131;
hash += key[i];//这个字符串转换成一个整形了就..
}
return hash;
}
};
bool Insert(const T& kv)
{
KeyofT kot;//获取K
if (findk(kot(kv)))
{
return false;
}
HashFunc hf;//转整形
if (_tabarry.size()==_n) //负载因子等于1,满了进行扩容
{
size_t newsize = GetNextPrime(_tabarry.size());
vector<Node*> newtabarry;
newtabarry.resize(newsize,nullptr);
for (size_t i = 0; i < _tabarry.size(); i++)
{
Node* cur = _tabarry[i];
while (cur)
{
Node* next = cur->_next;
size_t index = hf(kot(cur->_data)) & newsize;
cur->_next = newtabarry[index];//头插
newtabarry[index] = cur;
cur = next;
}
_tabarry[i] = nullptr;//数组的每个元素置空。
}
newtabarry.swap(_tabarry);// newarry 出了作用域自动析构...start,finsh,endof
}
size_t index = hf(kot(kv)) % _tabarry.size();
Node* cur = _tabarry[index];
while (cur) //单链表
{
if (kot(cur->_data)==kot(kv)) //如果有存在的就返回
{
return false;
}
else
{
cur = cur->_next;
}
}
Node* newnode = new Node(kv);
newnode->_next = _tabarry[index];
_tabarry[index] = newnode;
++_n;
return true;
}
Node* findk(const K& key)
{
HashFunc hf;//转整形
KeyofT kot;//获取K
if (_n==_tabarry.size())
{
return nullptr;
}
size_t index = hf(key) % _tabarry.size();
Node* cur = _tabarry[index];
while (cur)
{
if (kot(cur->_data)==key)
{
return cur;
}
cur = cur->_next;
}
return nullptr;
}
---
bool Erase(const K& key)
{
if (_tabarry.size()==0)
{
return false;
}
KeyofT kot;
HashFunc hf;
size_t del = hf(key) % _tabarry.size();
Node* cur = _tabarry[del];
Node* prev = nullptr;
while (cur)
{
if (kot(cur->_data) == key)
{
//相等可能是头节点。也可能是中间
if (prev==nullptr)
{
_tabarry[del] = cur->_next;
}
else
{
prev->_next = cur->_next;
}
delete cur;
--_n;
return true;
}
else
{
prev = cur;
cur = cur->_next;
}
}
return false;
}
iterator
template<class K, class T, class HashFunc, class KeyofT>
class HashTable;//前置声明
template<class K, class T, class HashFunc = HashFunc<K>, class KeyofT = KeyofT<K, T>>
struct Hashiterator
{
typedef HashData<T> HD;
typedef HashTable<K, T, HashFunc, KeyofT> HT;
typedef Hashiterator<K, T, HashFunc, KeyofT> Self;
HD* _node;
HT* _ht;
Hashiterator(HD* node, HT* ht)//用一个数据类型的指针初始化,这里还需要哈希表
:_node(node)
,_ht(ht)
{
}
Self& operator++()
{
KeyofT kot;
HashFunc hf;
size_t index = hf(kot(_node->_data)) % _ht->_tabarry.size();
HD* cur = _ht->_tabarry[index];
if (_node->_next)
{
_node = _node->_next;
}
else
{
++index;//跳过当前桶
_node = nullptr;
while (index < _ht->_tabarry.size())//小于数组的长度
{
if (_ht->_tabarry[index])
{
_node = _ht->_tabarry[index];
break;
}
else
{
++index;
}
}
if (index == _ht->_tabarry.size())//后面没桶了
{
_node = nullptr;
}
}
return *this;
}
bool operator!=(const Self& s) const
{
return _node != s._node;
}
T& operator*()
{
return _node->_data;
}
T* operator->()
{
return &_node->_data;
}
};
iterator begin() //找第一个桶,构造迭代器
{
for (size_t i = 0; i < _tabarry.size(); i++)
{
if (_tabarry[i])
{
return iterator(_tabarry[i], this);
}
}
return end();
}
iterator end()
{
return iterator(nullptr, this);
}
keyofT
来获取K的类型。[]
在这里额还是稳一点吧…
Come cheer up, my lads.Come cheer up, my lads.
振作起来吧,小伙子们.振作起来吧,小伙子们
'Tis better to have loved and lost
纵然曾经爱过却落空