负载因子
载荷因子
哈希冲突
闭散列
闭散列概念:
也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有 空位置,那么可以把key存放到冲突位置中的“下一个” 空位置中去。那如何寻找下一个空位置 呢?
用线性探测的方法:
先用key对数组大小取模,判断在下标为余数的位置上是否存在数据,如果存在则会查找下个元素是否存在,如果不存在就把数据存在此位置。存在就接着往下找
扩容条件:
当负载因子(哈希表元素个数和哈希表容量的比值)大于0.7
扩容方法:
在原数组进行扩容是不行的,不符合线性探测的规则,需要新建一个容量为原数组二倍的新数组
遍历原数组,按照线性探测的规则将数据拷贝到新数组里
插入数据:
插入数据之前需要判断是否需要扩容
在判断存储的位置,数据取模
数据个数自增1
元素状态改为存在(Exist)
删除数据:
先找到要删除的位置,对数据取模,判断元素状态(是否为 空,存在,还是删除)
如果找到状态为存在(Exist),把状态改为删除(delete)
哈希表数据个数自减1
查找数据
哈希表存的数据是pair<>类型,遍历哈希表,查找value值
代码部分
enum State
{
Empty,
Exist,
Delete
};
template<class K, class V>
class HashElement
{
public:
pair<K, V> _kv;
State _state = Empty;
};
class _mapfun
{
public:
int& operator()(int& data)
{
return data;
}
int operator()(string& data)
{
int sum = 0;
std::string::iterator it = data.begin();
while (it != data.end())
{
sum += *it;
it++;
}
return sum;
}
};
template<class K, class V, class mapfun = _mapfun >
class HashTable
{
public:
typedef HashElement<K, V> HElement;
vector<HashElement<K, V>> _arr;
int _size = 0;
HashTable()
{
_arr.resize(10);
}
public:
bool Insert(pair<K, V> data)
{
mapfun fun;
//扩容
if (_size * 10 / _arr.size() >= 7)
{
//创建新数组
vector<HElement>newarr;
newarr.resize(2 * _arr.size());
int i = 0;
for (i = 0; i < _arr.size(); i++)
{
if (_arr[i]._state == Exist)
{
//获取余数
int remainer = fun(_arr[i]._kv.first) % newarr.size();
if (newarr[remainer]._state == Empty)
{
newarr[remainer]._kv = _arr[i]._kv;
newarr[remainer]._state = Exist;
}
else
{
while (1)
{
remainer++;
if (remainer >= newarr.size())
remainer = 0;
if (newarr[remainer]._state == Empty)
{
newarr[remainer]._kv = _arr[i]._kv;
newarr[remainer]._state = Exist;
break;
}
}
}
}
}
swap(_arr, newarr);
}
int remainer = fun(data.first) % _arr.size();
while (1)
{
if (_arr[remainer]._state == Empty)
{
_arr[remainer]._kv = data;
_arr[remainer]._state = Exist;
_size++;
return 1;
}
remainer++;
if (remainer >= _arr.size())
{
remainer = 0;
}
}
}
HElement* Find(K key)
{
int remainer = key % _arr.size();
while (1)
{
if (_arr[remainer]._state == Exist && _arr[remainer]._kv.first == key)
{
return &_arr[remainer];
}
if (_arr[remainer]._state == Empty)
return nullptr;
remainer++;
}
}
bool Erase(K key)
{
if (Find(key) == nullptr)
{
return 0;
}
HElement* e = Find(key);
e->_state = Delete;
return 1;
}
};
开散列
开散列概念
发生哈希冲突时,把数据存在链表的下一位(或者是头都可以),首先还是要取模得到余数,找到要存的位置
也就是说哈西表元素是由链表构成的,
扩容方法
负载因子大于0.7时进行扩容,元素个数指的是所有链表中元素个数,哈希表的容量是能存多少链表的数量
创建新数组,容量为原先的二倍,进行数据转移
遍历原数组按照取模规则存到新数组,而为了减少删除和创建链表的消耗,把原数组链表节点连到新数组
代码部分
template<class K, class V>
class HashElement
{
public:
HashElement() = default;
pair<K, V> _kv;
HashElement<K, V>* _next=nullptr;
//State _state = Empty;
HashElement(pair<K,V>data)
{
_kv = data;
}
};
class _mapfun
{
public:
int& operator()(int& data)
{
return data;
}
int operator()(string& data)
{
int sum = 0;
std::string::iterator it = data.begin();
while (it != data.end())
{
sum += *it;
it++;
}
return sum;
}
};
template<class K, class V, class mapfun = _mapfun >
class HashTable
{
public:
typedef HashElement<K, V> HElement;
vector<HashElement<K, V>*> _arr;
int _size = 0;
HashTable()
{
_arr.resize(10);
}
public:
bool Insert(pair<K, V> data)
{
//判断扩容
if (_size * 10 / _arr.size()>=7)
{
int i = 0;
vector<HElement*> newtable;
newtable.resize(2 * _arr.size());
for (i = 0; i < _arr.size(); i++)
{
HElement* cur = _arr[i];
while (cur)
{
int remainer = cur->_kv.first % newtable.size();
if(newtable[remainer] == nullptr)
{
newtable[remainer] = cur;
newtable[remainer]->_next = nullptr;
cur = cur->_next;
}
else
{
HElement* next = cur->_next;
cur->_next = newtable[remainer];
newtable[remainer] = cur;
cur = next;
}
}
}
swap(_arr, newtable);
return 1;
}
int remainer = data.first % _arr.size();
if (_arr[remainer] == nullptr)
{
_arr[remainer] = new HElement(data);
}
else
{
HElement* newnode = new HElement(data);
newnode->_next = _arr[remainer];
_arr[remainer] = newnode;
}
_size++;
}
HElement* Find(K key)
{
int remainer = key % _arr.size();
HElement* cur = _arr[remainer];
while (cur)
{
if (cur->_kv.first == key)
return cur;
else
cur = cur->_next;
}
return nullptr;
}
bool Erase(K key)
{
if (Find(key) == nullptr)
{
return 0;
}
HElement* e = Find(key);
int remainer = key % _arr.size();
if (_arr[remainer] == e)
{
HElement* head = _arr[remainer];
_arr[remainer] = head->_next;
delete head;
return 1;
}
HElement* cur=_arr[remainer];
while (cur)
{
if (cur->_next == e)
break;
cur = cur->_next;
}
cur->_next = e->_next;
delete e;
return 1;
}
};