哈希表
总体表述
开发过程,经常需要对数据集合进行维护。
维护数据结合的数据结构可统称为容器。
哈希是维护数据集合的容器的一种,
本文所述的基于数组+双向链表的哈希表,
是综合了数组和链表的复合容器。
通过合理的哈希函数,
在最理想情况下,对n个元素,m个槽情况下,
每个槽均通过双向链表存储 n/m个元素。
这样向哈希表,上述理想情况下,
向哈希表插入元素时间复杂度Θ(1),
删除元素最多时间复杂度Θ(n/m),
搜索元素最多时间复杂度Θ(n/m)。
但由于哈希表,不具备数组的索引访问,排序,
且一般无法达到上述理想的效果。故实际上略显鸡肋。
接口设计
template<typename Key, typename Value>
class ListHash
{
public:
class Pair
{
public:
Pair()
{
}
Pair(const Key& nKey_, const Value& nValue_)
{
m_nKey = nKey_;
m_nValue = nValue_;
}
~Pair()
{
}
public:
Key m_nKey;
Value m_nValue;
};
public:
ListHash(int nSoltNums_,
std::function<int(const Key&, int)> hashFun_ = [](const Key& nKey_, int nSlotsNum_)->int
{
return (nKey_ % nSlotsNum_);
});
~ListHash();
ListHash(const ListHash& hash_);
ListHash& operator=(const ListHash& hash_);
void Insert(const Pair& nPair_);
void Delete(const Key& nKey_);
bool Search(const Key& nKey_, Value& nValue_) const;
private:
Array::DynArray<List::DoubleList<Pair>*> m_arrSlots;
std::function<int(const Key&, int)> m_fHashFun;
};
实现
构造
template<typename Key, typename Value>
ListHash<Key, Value>::ListHash(int nSoltNums_, std::function<int(const Key&, int)> hashFun_)
:m_arrSlots(nSoltNums_, nullptr), m_fHashFun(hashFun_)
{
for (int _i = 0; _i < nSoltNums_; _i++)
{
List::DoubleList<Pair>* _pList = nullptr;
try
{
_pList = new List::DoubleList<Pair>();
}
catch (...)
{
_pList = nullptr;
throw "out of memory";
}
m_arrSlots[_i] = _pList;
}
}
拷贝构造
template<typename Key, typename Value>
ListHash<Key, Value>::ListHash(const ListHash& hash_)
: m_arrSlots(hash_.m_arrSlots.GetSize(), nullptr), m_fHashFun(hash_.m_fHashFun)
{
int _nSize = hash_.m_arrSlots.GetSize();
for (int _i = 0; _i < _nSize; _i++)
{
List::DoubleList<Pair>* _pList = nullptr;
try
{
_pList = new List::DoubleList<Pair>(hash_.m_arrSlots[_i]);
}
catch (...)
{
_pList = nullptr;
throw "out of memory";
}
m_arrSlots[_i] = _pList;
}
}
赋值
template<typename Key, typename Value>
typename ListHash<Key, Value>& ListHash<Key, Value>::operator=(const ListHash& hash_)
{
if (this == &hash_)
{
return *this;
}
this->~ListHash();
int _nSize = hash_.m_arrSlots.GetSize();
m_arrSlots = Array::DynArray<List::DoubleList<Pair>*>(_nSize, nullptr);
for (int _i = 0; _i < _nSize; _i++)
{
List::DoubleList<Pair>* _pList = nullptr;
try
{
_pList = new List::DoubleList<Pair>(hash_.m_arrSlots[_i]);
}
catch (...)
{
_pList = nullptr;
throw "out of memory";
}
m_arrSlots[_i] = _pList;
}
m_fHashFun = hash_.m_fHashFun;
return *this;
}
析构
template<typename Key, typename Value>
ListHash<Key, Value>::~ListHash()
{
int _nSize = m_arrSlots.GetSize();
for (int _i = 0; _i < _nSize; _i++)
{
delete m_arrSlots[_i];
m_arrSlots[_i] = nullptr;
}
}
插入
template<typename Key, typename Value>
void ListHash<Key, Value>::Insert(const Pair& nPair_)
{
int _nSize = m_arrSlots.GetSize();
int _nIndex = m_fHashFun(nPair_.m_nKey, _nSize);
List::DoubleList<Pair> *_pList = m_arrSlots[_i];
_pList->Add(nPair_);
}
删除
template<typename Key, typename Value>
void ListHash<Key, Value>::Delete(Key nKey_)
{
int _nSize = m_arrSlots.GetSize();
int _nIndex = m_fHashFun(nKey_, _nSize);
List::DoubleList<Pair> *_pList = m_arrSlots[_nIndex];
List::DoubleList<Pair>::Node* _pNode = _pList->Find([nKey_](const Pair& nPair_)->bool
{
if (nPair_.m_nKey == nKey_)
{
return true;
}
else
{
return false;
}
});
if (_pNode)
{
_pList->Delete(_pNode);
}
}
搜索
template<typename Key, typename Value>
bool ListHash<Key, Value>::Search(const Key& nKey_, Value& nValue_) const
{
int _nSize = m_arrSlots.GetSize();
int _nIndex = m_fHashFun(nKey_, _nSize);
List::DoubleList<Pair> *_pList = m_arrSlots[_nIndex];
List::DoubleList<Pair>::Node* _pNode = _pList->Find([nKey_](const Pair& nPair_)->bool
{
if (nPair_.m_nKey == nKey_)
{
return true;
}
else
{
return false;
}
});
if (_pNode == nullptr)
{
return false;
}
else
{
Pair _nPair = _pNode->GetValue();
nValue_ = _nPair.m_nValue;
return true;
}
}
时间复杂度
假设元素个数n,槽个数m
假设可以达到理想效果,即每个槽中均有n/m个元素
构造
时间复杂度Θ(n)
拷贝构造
时间复杂度Θ(n)
赋值
时间复杂度Θ(n)
析构
时间复杂度Θ(n)
插入
时间复杂度Θ(1)
删除
时间复杂度O(n/m)
查找
时间复杂度O(n/m)