目录
HashTable.h:
Test.cpp:
MyUnorderedSet.h:
#pragma once
#include
#include
#include//pair头文件
#include
#include
using namespace std;
namespace CLOSEHASH
{
enum State
{
EMPTY, //空
EXIST, //存在
DELETE //删除
};
template
struct HashData
{
T _data;
State _state; //代表数据状态
HashData()
:_state(EMPTY)
,_data(0)
{}
};
template
class HashTable
{
typedef HashData HashData;
public:
bool Insert(const T& data)
{
KeyOfT koft;
//1、增容:第一次插入或者负载因子>=0.7就要增容
if (_tables.capacity() == 0 || _num * 10 / _tables.capacity() == 7)
{
//A、增容——传统思路
//vector newtables;
//size_t newcapacity = _tables.capacity() == 0 ? 10 : _tables.capacity() * 2;
//newtables.resize(newcapacity);//开空间+自动初始化为0
把旧空间数据拷贝到新空间中
//for (size_t i = 0; i < _tables.capacity(); ++i)
//{
// if (_tables[i]._state == EXIST)
// {
// size_t index = koft(_tables[i]._data) % newtables.capacity();
// while (newtables[index]._state == EXIST)
// {
// index++;
// if (index == newtables.capacity())
// {
// index = 0;//走到尾了就要返回头找位置
// }
// }
// newtables[index] = _tables[i];
// }
//}
//_tables.swap(newtables);
//B、增容——简便思路
HashTable newht;
size_t newcapacity = _tables.capacity() == 0 ? 10 : _tables.capacity() * 2;
newht._tables.resize(newcapacity);
for (size_t i = 0; i < _tables.capacity(); ++i)
{
if (_tables[i]._state == EXIST)
{
newht.Insert(_tables[i]._data);//把原哈希表中每个数据利用Insert都插入到新哈希表中
}
}
_tables.swap(newht._tables);//交换两者的vector
}
//1、线性探测
//size_t index = koft(data) % _tables.capacity();//计算出要映射的位置
//while (_tables[index]._state == EXIST)
//{
// if (koft(_tables[index]._data) == koft(data))
// {
// return false;//如果存在相同的数据
// }
// ++index;
// if (index == _tables.capacity())
// {
// index = 0;
// }
//}
//2、二次探测
size_t start = koft(data) % _tables.capacity();
size_t index = start;
int i = 1;
while (_tables[index]._state == EXIST)
{
if (koft(_tables[index]._data) == koft(data))
{
return false;
}
index = start + i * i;
++i;
index %= _tables.capacity();
}
//插入数据
_tables[index]._data = data;
_tables[index]._state = EXIST;
++_num; //有效数据个数++
return true;
}
HashData* Find(const K& key)
{
KeyOfT koft;
size_t index = key % _tables.capacity();
while(_tables[index]._state != EMPTY)
{//只要是存在和删除状态就要持续往下找
if (koft(_tables[index]._data) == key)
{
if (_tables[index]._state == EXIST)
return &_tables[index];//值相等且为存在状态
else
return nullptr;//值相等但为删除状态,说明被删除了
}
++index;//没找到继续往后找
index %= _tables.capacity();
}
return nullptr;
}
bool Erase(const K& key)
{
HashData* ret = Find(key);
if (ret)
{
ret->_state = DELETE;//用状态代表删除状态
--_num; //--有效元素个数
return true;
}
else
{
return false;
}
}
private:
vector _tables;
size_t _num = 0; //表中存了多少个有效个数,不等于容量
};
}
namespace OPENHASH
{
template
struct HashNode
{
T _data;
HashNode* _next;
HashNode(const T& data)
:_data(data)
, _next(nullptr)
{}
};
//前置声明:为了让哈希表的迭代器能用哈希表
template
class HashTable;
template
struct __HashTableIterator
{
typedef __HashTableIterator Self;
typedef HashTable HT;
typedef HashNode Node;
Node* _node;//迭代器中存的是节点指针
HT* _pht;//对象的指针
__HashTableIterator(Node* node, HT* pht)
:_node(node)
,_pht(pht)
{}
T& operator*()
{
return _node->_data;
}
T* operator->()
{
return &_node->_data;
}
Self operator++()
{
if (_node->_next)
{
_node = _node->_next;
}
else
{
// 如果一个桶走完了,要往下找到下一个桶继续遍历
KeyOfT koft;
//先计算我当前是在哪个桶
size_t i = _pht->HashFunc(koft(_node->_data)) % _pht->_tables.capacity();
++i;//下一个桶
for (; i < _pht->_tables.capacity(); ++i)
{ //找不为空的桶
Node* cur = _pht->_tables[i];
if (cur)
{ //如果这个桶不为空
_node = cur;
return *this;
}
}
_node = nullptr;//如果没有找到有数据的桶,则指针置为空,与end()相符
return *this;
}
}
bool operator!=(const Self& s)
{
return _node != s._node;
}
};
template
struct _Hash
{
const K& operator()(const K& key)
{
return key;//可以取模的直接返回即可
}
};
//特化
template<>
struct _Hash
{
size_t operator()(const string& key)
{
//运用BKDR Hash算法
size_t hash = 0;
for (size_t i = 0; i < key.size(); ++i)
{
hash *= 131; //BKDR
hash += key[i];//字符串中每个字母ASCII码值相加
}
return hash;
}
};
template
class HashTable
{
typedef HashNode Node;
public:
friend struct __HashTableIterator;//因为迭代器要访问哈希表的私有成员_tables
typedef __HashTableIterator iterator;
//begin()返回第一个不为空的桶的第一个节点
iterator begin()
{
for (size_t i = 0; i < _tables.capacity(); ++i)
{
if (_tables[i])
{
return iterator(_tables[i], this);//找到了则构造匿名对象返回
}
}
return end();//每个桶中都没找到则返回end()
}
iterator end()
{
return iterator(nullptr, this);
}
size_t HashFunc(const K& key)
{
Hash hash;
return hash(key);//利用仿函数把key值转为整形
}
size_t GetNextPrime(size_t num)
{
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
};
for (size_t i = 0;; i < PRIMECOUNT; ++i)
{
if (primeList[i] > num)
return primeList[i];
}
return primeList[PRIMECOUNT - 1];//如果num比我表中所有数据都大,默认返回表中最后一个
}
pair Insert(const T& data)
{
KeyOfT koft;
//1、判断是否增容
if (_tables.capacity() == _num)
{ //开散列的实现平衡因子为1就增容且第一次插入也会增容
//size_t newcapacity = _tables.capacity() == 0 ? 10 : _tables.capacity() * 2;
size_t newcapacity = GetNextPrime(_tables.capacity());
vector newtables;
newtables.resize(newcapacity, nullptr);//给新的vector开新空间+初始化
//重新计算旧表的数据在新表中的映射位置
for (size_t i = 0; i < _tables.capacity(); ++i)
{ //如果是第一次的增容不会进for循环的,故不用担忧表的初始数据是否为nullptr
//哈希表中每一个桶都是一个单链表,故考察单链表的头插
Node* cur = _tables[i];
while (cur)
{
Node* next = cur->_next;
size_t index = HashFunc(koft(cur->_data)) % newtables.capacity();//重新计算映射位置
//头插
cur->_next = newtables[index];
newtables[index] = cur;
cur = next;
}
_tables[i] = nullptr;//映射到新表后置为空
}
_tables.swap(newtables);//新旧表的vector交换
}
size_t index = HashFunc(koft(data)) % _tables.capacity();//计算新的映射位置
//1、先查找这个元素是否在哈希表中
Node* cur = _tables[index];//知道映射位置就能确定是哪个桶
while (cur)
{
if (koft(cur->_data) == koft(data))
return make_pair(iterator(cur, this), false);//找到相同数据则插入失败
else
cur = cur->_next;
}
//2、头插到这个桶中
Node* newnode = new Node(data);//开辟新节点
//头插
newnode->_next = _tables[index];
_tables[index] = newnode;
++_num;//哈希表中有效元素个数++
return make_pair(iterator(newnode, this), false);
}
Node* Find(const K& key)
{
KeyOfT koft;
size_t index = HashFunc(key) % _tables.capacity();//先计算映射位置
Node* cur = _tables[index];
while (cur)
{
if (koft(cur->_data) == key)
return cur;
else
cur = cur->_next;
}
return nullptr;//走遍桶都没找到则返回空
}
bool Erase(const K& key)
{
assert(_tables.capacity() > 0);//有空间才能删
KeyOfT koft;
size_t index = HashFunc(key) % _tables.capacity();
Node* cur = _tables[index];
Node* prev = nullptr;//记录cur的前一位置
while (cur)
{
if (koft(cur->_data) == key)
{
if (prev == nullptr)
{ //如果是头删
_tables[index] = cur->_next;
}
else
{
prev->_next = cur->_next;
}
delete cur;
--_num;
return true;
}
else
{
prev = cur;
cur = cur->_next;
}
}
return false;//要删除数据根本不存在
}
~HashTable()
{
Clear();
//vector不用我们释放,因为它是自定义类型,哈希表要清理时,vector也会自动清理
}
void Clear()
{
for (size_t i = 0; i < _tables.capacity(); ++i)
{
Node* cur = _tables[i];
while (cur)
{
Node* next = cur->_next;
delete cur;
cur = next;
}
_tables[i] = nullptr;//清空完数据后置为nullptr
}
}
private:
vector _tables; //使用vector一定要包含std库,不然使用不了
size_t _num = 0; //有效元素的个数,不是容量
};
}
#include"HashTable.h"
#include"MyUnorderedMap.h"
#include"MyUnorderedSet.h"
template
struct SetKeyOfT
{
const K& operator()(const K& key)
{
return key;
}
};
void TestCloseHash()
{
CLOSEHASH::HashTable> ht;
//CLOSEHASH::HashTable> ht2;
ht.Insert(2);
ht.Insert(4);
ht.Insert(14);
ht.Insert(24);
ht.Insert(26);
ht.Insert(16);
ht.Erase(14);
ht.Erase(2);
CLOSEHASH::HashData* data = ht.Find(4);
}
void TestOpenHash1()
{
using OPENHASH::_Hash;
OPENHASH::HashTable, _Hash> ht;
//OPENHASH::HashTable> ht2;
ht.Insert(2);
ht.Insert(4);
ht.Insert(14);
ht.Insert(24);
ht.Insert(26);
ht.Insert(16);
ht.Erase(14);
ht.Erase(2);
OPENHASH::HashNode* Node = ht.Find(4);
/*ht2.Insert(make_pair(1,1));
ht2.Insert(4);
ht2.Insert(14);
ht2.Insert(24);
ht2.Insert(26);
ht2.Insert(16);
ht2.Erase(14);
ht2.Erase(2);
HashNode* Node2 = ht2.Find(4);*/
}
void TestOpenHash2()
{
using OPENHASH::_Hash;
OPENHASH::HashTable,_Hash> ht;
ht.Insert("sort");
ht.Insert("futile");
ht.Insert("plight");
cout << ht.HashFunc("abcd") << endl;
cout << ht.HashFunc("aadd") << endl;
}
int main()
{
//TestCloseHash();
//TestOpenHash1();
//TestOpenHash2();
//mz::test_unordered_set();
mz::test_unordered_map();
return 0;
}
#pragma once
#include"HashTable.h"
using namespace OPENHASH;
namespace mz
{
using OPENHASH::_Hash;
template>
class unordered_set
{
struct SetKOfT
{
const K& operator()(const K& k)
{
return k;
}
};
public:
//加typename是告诉编译器这是个类型,你先让我过,等实例化了再去找
//因为模板没实例化它是不接受你用模板里面的一个类型,故要用typename
typedef typename HashTable::iterator iterator;
iterator begin()
{
return _ht.begin();
}
iterator end()
{
return _ht.end();
}
pair insert(const K& k)
{
return _ht.Insert(k);
}
private:
HashTable _ht;
};
void test_unordered_set()
{
unordered_set s;
s.insert(1);
s.insert(5);
s.insert(4);
s.insert(2);
unordered_set::iterator it = s.begin();
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
}
MyUnorderedMap.h:
#pragma once
#include"HashTable.h"
using namespace OPENHASH;
namespace mz
{
using OPENHASH::_Hash;
template>//一般模板参数都是由上一层来控制的
class unordered_map
{
struct MapKOfT
{
const K& operator()(const pair& kv)
{
return kv.first;
}
};
public:
typedef typename HashTable, MapKOfT, Hash>::iterator iterator;
iterator begin()
{
return _ht.begin();
}
iterator end()
{
return _ht.end();
}
pair insert(const pair& kv)
{
return _ht.Insert(kv);
}
V& operator[](const K& key)
{
pair ret = _ht.Insert(make_pair(key, V()));
return ret.first->second;
}
private:
HashTable, MapKOfT, Hash> _ht;//底层是个哈希表
};
void test_unordered_map()
{
unordered_map dict;
dict.insert(make_pair("factual", "真实的"));
dict.insert(make_pair("fringe", "侵犯"));
dict.insert(make_pair("intermittent", "间歇的"));
dict["prerequisite"] = "先决条件";
dict["reduce to"] = "处于";
//unordered_map::iterator it = dict.begin();
auto it = dict.begin();
while (it != dict.end())
{
cout << it->first << ":" << it->second << endl;
++it;
}
cout << endl;
}
}