This commit is contained in:
commit
77b0d6f6de
685
Linux/HashTable.hpp
Normal file
685
Linux/HashTable.hpp
Normal file
@ -0,0 +1,685 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
// unordered_set<K> -> HashTable<K, K>
|
||||
// unordered_map<K, V> -> HashTable<K, pair<K, V>>
|
||||
|
||||
namespace Lenyiin
|
||||
{
|
||||
template <class K>
|
||||
struct SetKeyOfT
|
||||
{
|
||||
const K &operator()(const K &key)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
};
|
||||
|
||||
enum State
|
||||
{
|
||||
EMPTY, // 槽位为空
|
||||
EXIST, // 槽位已经存在一个元素
|
||||
DELETE // 槽位中元素被删除
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct HashData
|
||||
{
|
||||
T _data;
|
||||
State _state;
|
||||
|
||||
HashData()
|
||||
: _data(T()), _state(EMPTY)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <class K, class T, class KeyOfT>
|
||||
class Close_HashTable
|
||||
{
|
||||
private:
|
||||
typedef struct HashData<T> HashData;
|
||||
|
||||
size_t SecondHash(const K &key, size_t table_size)
|
||||
{
|
||||
return 1 + (key % (table_size - 1));
|
||||
}
|
||||
|
||||
public:
|
||||
// 负载因子 = 表中数据/表的大小 衡量哈希表满的程度
|
||||
// 表越接近满, 插入数据越容易冲突, 冲突越多, 效率越低
|
||||
// 哈希表并不是满了才增容, 开放定制法中, 一般负载因子到 0.7 左右就开始增容
|
||||
// 负载因子越小, 冲突概率越低, 整体效率越高, 但是负载因子越小, 浪费的空间越大, 所以负载因子一般取一个折中的值
|
||||
void CheckCapacity()
|
||||
{
|
||||
KeyOfT koft;
|
||||
|
||||
// // version 1
|
||||
// if (_tables.size() == 0 || _num * 10 / _tables.size() >= 7)
|
||||
// {
|
||||
// // 增容
|
||||
// // 1. 开 2倍大小的新表
|
||||
// // 2. 遍历旧表的数据,重新计算在新表中位置
|
||||
// // 3. 释放旧表
|
||||
// std::vector<HashData> newtables;
|
||||
// size_t newsize = _tables.size() == 0 ? 10 : _tables.size() * 2;
|
||||
// newtables.resize(newsize);
|
||||
// for (size_t i = 0; i < _tables.size(); i++)
|
||||
// {
|
||||
// if (_tables[i]._state == EXIST)
|
||||
// {
|
||||
// // 计算在新表中的位置, 并处理冲突
|
||||
// size_t index = koft(_tables[i]._data) % newtables.size();
|
||||
// while (newtables[index]._state == EXIST)
|
||||
// {
|
||||
// ++index;
|
||||
// if (index == _tables.size())
|
||||
// {
|
||||
// index = 0;
|
||||
// }
|
||||
// }
|
||||
// newtables[index] = _tables[i];
|
||||
// }
|
||||
// }
|
||||
// _tables.swap(newtables);
|
||||
// }
|
||||
|
||||
// // version 2
|
||||
// if (_tables.size() == 0 || _num * 10 / _tables.size() >= 7)
|
||||
// {
|
||||
// // 增容
|
||||
// // 1. 开 2倍大小的新表
|
||||
// // 2. 遍历旧表的数据,重新计算在新表中位置
|
||||
// // 3. 释放旧表
|
||||
// std::vector<HashData> newtables;
|
||||
// size_t newsize = _tables.size() == 0 ? 10 : _tables.size() * 2;
|
||||
// newtables.resize(newsize);
|
||||
// for (size_t i = 0; i < _tables.size(); i++)
|
||||
// {
|
||||
// if (_tables[i]._state == EXIST)
|
||||
// {
|
||||
// // 重新计算新表中的位置
|
||||
// size_t index = koft(_tables[i]._data) % newtables.size();
|
||||
// size_t step = SecondHash(koft(_tables[i]._data), newtables.size());
|
||||
|
||||
// // 处理冲突:双重哈希探测
|
||||
// while (newtables[index]._state == EXIST)
|
||||
// {
|
||||
// index = (index + step) % newtables.size();
|
||||
// }
|
||||
|
||||
// // 插入元素到新表
|
||||
// newtables[index] = _tables[i];
|
||||
// }
|
||||
// }
|
||||
// _tables.swap(newtables);
|
||||
// }
|
||||
|
||||
// version 3
|
||||
// 另一种增容思路
|
||||
if (_tables.size() == 0 || _num * 10 / _tables.size() >= 7)
|
||||
{
|
||||
Close_HashTable<K, T, KeyOfT> newht;
|
||||
size_t newsize = _tables.size() == 0 ? 10 : _tables.size() * 2;
|
||||
newht._tables.resize(newsize);
|
||||
for (size_t i = 0; i < _tables.size(); i++)
|
||||
{
|
||||
if (_tables[i]._state == EXIST)
|
||||
{
|
||||
newht.Insert(_tables[i]._data);
|
||||
}
|
||||
}
|
||||
_tables.swap(newht._tables);
|
||||
}
|
||||
}
|
||||
|
||||
bool Insert(const T &data)
|
||||
{
|
||||
KeyOfT koft;
|
||||
|
||||
CheckCapacity();
|
||||
// 闭散列中线性探测有什么问题?
|
||||
// 线性探测思路就是我的位置被占了, 我就挨着往后去占别人的位置, 可能会导致一片一片的冲突, 洪水效应
|
||||
|
||||
// version 1
|
||||
// 线性探测
|
||||
// 计算 data 中的 key 在表中映射的位置
|
||||
// size_t index = koft(data) % _tables.size();
|
||||
// while (_tables[index]._state == EXIST)
|
||||
// {
|
||||
// if (koft(_tables[index]._data) == koft(data))
|
||||
// {
|
||||
// return false; // 已经存在
|
||||
// }
|
||||
// ++index;
|
||||
// if (index == _tables.size())
|
||||
// {
|
||||
// index = 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
// version 2
|
||||
// 二次探测
|
||||
// 计算 data 中的 key 在表中映射的位置
|
||||
// size_t start = koft(data) % _tables.size();
|
||||
// size_t index = start;
|
||||
// int i = 0;
|
||||
// while (_tables[index]._state == EXIST)
|
||||
// {
|
||||
// if (koft(_tables[index]._data) == koft(data))
|
||||
// {
|
||||
// return false; // 已经存在
|
||||
// }
|
||||
// index = start + i * i;
|
||||
// i++;
|
||||
// index %= _tables.size();
|
||||
// }
|
||||
|
||||
// version 3
|
||||
// 双重哈希
|
||||
size_t index = koft(data) % _tables.size();
|
||||
size_t step = SecondHash(koft(data), _tables.size());
|
||||
while (_tables[index]._state == EXIST)
|
||||
{
|
||||
if (koft(_tables[index]._data) == koft(data))
|
||||
{
|
||||
return false; // 如果找到相同的 key,插入失败
|
||||
}
|
||||
|
||||
index = (index + step) % _tables.size(); // 使用双重哈希计算下一个位置
|
||||
}
|
||||
|
||||
_tables[index]._data = data;
|
||||
_tables[index]._state = EXIST;
|
||||
++_num;
|
||||
|
||||
// 我么可以看到闭散列-开放定制法不是一种好的解决方式, 因为它是一种我的位置被占了, 我就去抢占别人的位置的思路
|
||||
// 也就是说他的哈希冲突会相互影响, 我冲突占你的, 你冲突占他的, 他冲突了... , 没完没了, 整体的效率都变低了
|
||||
// 开散列的哈希桶可以解决上面的问题
|
||||
return true;
|
||||
}
|
||||
|
||||
// 线性探测
|
||||
// HashData *Find(const K &key)
|
||||
// {
|
||||
// KeyOfT koft;
|
||||
// // 计算 data 中的 key 在表中映射的位置
|
||||
// size_t index = key % _tables.size();
|
||||
// while (_tables[index]._state != EMPTY)
|
||||
// {
|
||||
// if (koft(_tables[index]._data) == key)
|
||||
// {
|
||||
// if (_tables[index]._state == EXIST)
|
||||
// {
|
||||
// return &_tables[index];
|
||||
// }
|
||||
// else if (_tables[index]._state == DELETE)
|
||||
// {
|
||||
// return nullptr;
|
||||
// }
|
||||
// }
|
||||
// ++index;
|
||||
// if (index == _tables.size())
|
||||
// {
|
||||
// index = 0;
|
||||
// }
|
||||
// }
|
||||
// return nullptr;
|
||||
// }
|
||||
|
||||
// 双重哈希
|
||||
HashData *Find(const K &key)
|
||||
{
|
||||
KeyOfT koft;
|
||||
size_t index = key % _tables.size();
|
||||
size_t step = SecondHash(key, _tables.size()); // 计算步长
|
||||
while (_tables[index]._state != EMPTY)
|
||||
{
|
||||
if (koft(_tables[index]._data) == key)
|
||||
{
|
||||
if (_tables[index]._state == EXIST)
|
||||
{
|
||||
return &_tables[index];
|
||||
}
|
||||
else if (_tables[index]._state == DELETE)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
index = (index + step) % _tables.size(); // 使用双重哈希探测下一个位置
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Erase(const K &key)
|
||||
{
|
||||
HashData *ret = Find(key);
|
||||
if (ret)
|
||||
{
|
||||
ret->_state = DELETE;
|
||||
--_num;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
HashData &getHashData(int pos)
|
||||
{
|
||||
return _tables[pos];
|
||||
}
|
||||
|
||||
void Print()
|
||||
{
|
||||
int size = _tables.size();
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
std::cout << i << "\t";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
auto cur = _tables[i];
|
||||
if (cur._state == EXIST)
|
||||
{
|
||||
std::cout << cur._data << "\t";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "*\t";
|
||||
}
|
||||
}
|
||||
std::cout << "\n\n";
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<HashData> _tables;
|
||||
size_t _num = 0; // 存储了几个有效数据
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct HashNode
|
||||
{
|
||||
T _data; // 存储数据
|
||||
HashNode<T> *_next; // 存储下一个节点
|
||||
|
||||
// 如果想要实现迭代顺序为插入顺序, 可以加两个指针组成一个链表
|
||||
// HashNode<T>* _linknext;
|
||||
// HashNode<T>* _linkprev;
|
||||
|
||||
HashNode(const T &data)
|
||||
: _data(data), _next(nullptr)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// 前置声明
|
||||
template <class K, class T, class KeyOfT, class Hash>
|
||||
class Open_HashTable;
|
||||
|
||||
// 哈希表只有单向迭代器, 只有 ++, 没有--
|
||||
template <class K, class T, class KeyOfT, class Hash>
|
||||
struct __HashTableIterator
|
||||
{
|
||||
typedef __HashTableIterator<K, T, KeyOfT, Hash> Self;
|
||||
typedef Open_HashTable<K, T, KeyOfT, Hash> HT;
|
||||
typedef HashNode<T> 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 index = _pht->HashFunc(koft(_node->_data)) % _pht->_tables.size();
|
||||
++index;
|
||||
while (index < _pht->_tables.size())
|
||||
{
|
||||
Node *cur = _pht->_tables[index];
|
||||
if (cur)
|
||||
{
|
||||
_node = cur;
|
||||
return *this;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
_node = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Self operator++(int)
|
||||
{
|
||||
Self tmp(*this);
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator!=(const Self &s)
|
||||
{
|
||||
return _node != s._node;
|
||||
}
|
||||
|
||||
bool operator==(const Self &s)
|
||||
{
|
||||
return _node == s._node;
|
||||
}
|
||||
};
|
||||
|
||||
template <class K>
|
||||
struct _Hash
|
||||
{
|
||||
const K &operator()(const K &key)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
};
|
||||
|
||||
// 特化
|
||||
template <>
|
||||
struct _Hash<std::string>
|
||||
{
|
||||
size_t operator()(const std::string &key)
|
||||
{
|
||||
// BKDR Hash
|
||||
size_t hash = 0;
|
||||
for (size_t i = 0; i < key.size(); i++)
|
||||
{
|
||||
hash *= 131;
|
||||
hash += key[i];
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
struct _HashString
|
||||
{
|
||||
size_t operator()(const std::string &key)
|
||||
{
|
||||
// BKDR Hash
|
||||
size_t hash = 0;
|
||||
for (size_t i = 0; i < key.size(); i++)
|
||||
{
|
||||
hash *= 131;
|
||||
hash += key[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
template <class K, class T, class KeyOfT, class Hash>
|
||||
// template <class K, class T, class KeyOfT, class Hash = _Hash<K>>
|
||||
class Open_HashTable
|
||||
{
|
||||
private:
|
||||
typedef HashNode<T> Node;
|
||||
|
||||
public:
|
||||
friend struct __HashTableIterator<K, T, KeyOfT, Hash>;
|
||||
typedef __HashTableIterator<K, T, KeyOfT, Hash> iterator;
|
||||
|
||||
iterator begin()
|
||||
{
|
||||
for (size_t i = 0; i < _tables.size(); i++)
|
||||
{
|
||||
if (_tables[i])
|
||||
{
|
||||
return iterator(_tables[i], this);
|
||||
}
|
||||
}
|
||||
return end();
|
||||
}
|
||||
|
||||
iterator end()
|
||||
{
|
||||
return iterator(nullptr, this);
|
||||
}
|
||||
|
||||
Open_HashTable()
|
||||
{
|
||||
}
|
||||
|
||||
Open_HashTable(size_t bucket_count)
|
||||
: _tables(bucket_count), _num(0)
|
||||
{
|
||||
}
|
||||
|
||||
~Open_HashTable()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
for (size_t i = 0; i < _tables.size(); i++)
|
||||
{
|
||||
Node *cur = _tables[i];
|
||||
while (cur)
|
||||
{
|
||||
Node *next = cur->_next;
|
||||
delete cur;
|
||||
cur = next;
|
||||
}
|
||||
_tables[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
size_t HashFunc(const K &key)
|
||||
{
|
||||
Hash hash;
|
||||
return hash(key);
|
||||
}
|
||||
|
||||
size_t GetNextPrime(size_t num)
|
||||
{
|
||||
const int PrimeSize = 28;
|
||||
static const unsigned long PrimeList[PrimeSize] =
|
||||
{
|
||||
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 < PrimeSize; i++)
|
||||
{
|
||||
if (PrimeList[i] > num)
|
||||
{
|
||||
return PrimeList[i];
|
||||
}
|
||||
}
|
||||
|
||||
return PrimeList[PrimeSize - 1]; // 如果已经是最后一个数的, 则不增容
|
||||
}
|
||||
|
||||
// 重新哈希
|
||||
void Rehash(size_t newsize)
|
||||
{
|
||||
KeyOfT koft;
|
||||
std::vector<Node *> newtables;
|
||||
newtables.resize(newsize);
|
||||
for (size_t i = 0; i < _tables.size(); i++)
|
||||
{
|
||||
// 将旧表中的节点取下来, 重新计算在新表中的位置, 并插入进去
|
||||
Node *cur = _tables[i];
|
||||
while (cur)
|
||||
{
|
||||
Node *next = cur->_next;
|
||||
size_t index = HashFunc(koft(cur->_data)) % newtables.size();
|
||||
cur->_next = newtables[index];
|
||||
newtables[index] = cur;
|
||||
cur = next;
|
||||
}
|
||||
_tables[i] = nullptr;
|
||||
}
|
||||
_tables.swap(newtables);
|
||||
}
|
||||
|
||||
// 插入操作
|
||||
// 当大量的数据冲突, 这些哈希冲突的数据就会挂在同一个链式桶中, 查找时效率就会降低, 所以开散列-哈希桶也是要控制哈希冲突的。
|
||||
// 如何控制呢? 通过控制负载因子, 不过这里就把空间利用率提高一些, 负载因子也可以高一些, 一般开散列把负载因子控制到1, 会比较好一点
|
||||
std::pair<iterator, bool> Insert(const T &data)
|
||||
{
|
||||
KeyOfT koft;
|
||||
|
||||
// 1. 检查负载因子
|
||||
// 如果负载因子等于 1 , 则增容, 避免大量的哈希冲突
|
||||
if (_tables.size() == _num)
|
||||
{
|
||||
// 1. 开两倍大小的新表(不一定是两倍)
|
||||
// 2. 遍历旧表的数据, 重新计算在新表中的位置
|
||||
// 3. 释放旧表
|
||||
size_t newsize = _tables.size() == 0 ? 10 : _tables.size() * 2;
|
||||
// size_t newsize = GetNextPrime(_tables.size());
|
||||
|
||||
Rehash(newsize);
|
||||
}
|
||||
|
||||
// 2. 计算数据在表中映射的位置
|
||||
size_t index = HashFunc(koft(data)) % _tables.size();
|
||||
|
||||
// 3. 先查找这个值在不在表中, 是否有冲突
|
||||
Node *cur = _tables[index];
|
||||
while (cur)
|
||||
{
|
||||
if (HashFunc(koft(cur->_data)) == HashFunc(koft(data)))
|
||||
{
|
||||
// 如果已经存在该键,返回失败
|
||||
return std::make_pair(iterator(cur, this), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 查找下一个节点
|
||||
cur = cur->_next;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 头插挂到链表中(尾插也是可以的)
|
||||
Node *newnode = new Node(data);
|
||||
newnode->_next = _tables[index];
|
||||
_tables[index] = newnode;
|
||||
|
||||
++_num; // 更新已存储元素数量
|
||||
return std::make_pair(iterator(newnode, this), true);
|
||||
}
|
||||
|
||||
// 查找操作
|
||||
Node *Find(const K &key)
|
||||
{
|
||||
KeyOfT koft;
|
||||
|
||||
// 1. 计算键在表中映射的位置
|
||||
size_t index = HashFunc(key) % _tables.size();
|
||||
Node *cur = _tables[index];
|
||||
|
||||
// 2. 遍历链表查找匹配的键
|
||||
while (cur)
|
||||
{
|
||||
if (HashFunc(koft(cur->_data)) == HashFunc(key))
|
||||
{
|
||||
// 如果找到匹配的元素,返回其指针
|
||||
return cur;
|
||||
}
|
||||
// 继续查找下一个节点
|
||||
cur = cur->_next;
|
||||
}
|
||||
// 如果未找到,返回空指针
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Erase(const K &key)
|
||||
{
|
||||
KeyOfT koft;
|
||||
|
||||
// 1. 计算要删除元素的哈希值
|
||||
size_t index = HashFunc(key) % _tables.size();
|
||||
Node *prev = nullptr;
|
||||
Node *cur = _tables[index];
|
||||
|
||||
// 2. 遍历链表, 查找匹配的元素
|
||||
while (cur)
|
||||
{
|
||||
if (HashFunc(koft(cur->_data)) == HashFunc(key))
|
||||
{
|
||||
// 3. 找到元素后, 调整链表结构
|
||||
if (prev == nullptr)
|
||||
{
|
||||
// 如果要删除的元素是链表的第一个节点, 直接让桶指向下一个节点
|
||||
_tables[index] = cur->_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 否则,将前一个节点的 next 指向当前节点的下一个节点
|
||||
prev->_next = cur->_next;
|
||||
}
|
||||
// 4. 释放节点内存
|
||||
delete cur;
|
||||
--_num; // 元素数量减少
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 继续遍历链表
|
||||
prev = cur;
|
||||
cur = cur->_next;
|
||||
}
|
||||
}
|
||||
// 如果未找到该元素,返回 false
|
||||
return false;
|
||||
}
|
||||
|
||||
void Print() const
|
||||
{
|
||||
KeyOfT koft;
|
||||
int size = _tables.size();
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
std::cout << i << "\t";
|
||||
Node *cur = _tables[i];
|
||||
while (cur)
|
||||
{
|
||||
std::cout << koft(cur->_data) << "\t";
|
||||
cur = cur->_next;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Node *> _tables; // 哈希表存储桶
|
||||
size_t _num; // 记录着存储的数据个数
|
||||
};
|
||||
}
|
324
Linux/Main.cc
Normal file
324
Linux/Main.cc
Normal file
@ -0,0 +1,324 @@
|
||||
#include "Unordered_Set.hpp"
|
||||
#include "Unordered_Map.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <time.h>
|
||||
|
||||
void Test_unordered_set()
|
||||
{
|
||||
std::unordered_set<int> us; // Java里面取名叫HashSet
|
||||
us.insert(4);
|
||||
us.insert(2);
|
||||
us.insert(1);
|
||||
std::cout << "us 的 bucket 数量是: " << us.bucket_count()
|
||||
<< "\tus 的 负载因子 是: " << us.load_factor() << std::endl;
|
||||
us.insert(5);
|
||||
us.insert(6);
|
||||
us.insert(3);
|
||||
us.insert(5);
|
||||
us.insert(6);
|
||||
us.insert(3);
|
||||
us.insert(15);
|
||||
us.insert(16);
|
||||
us.insert(13);
|
||||
std::cout << "us 的 bucket 数量是: " << us.bucket_count()
|
||||
<< "\tus 的 负载因子 是: " << us.load_factor() << std::endl;
|
||||
us.insert(15);
|
||||
us.insert(16);
|
||||
us.insert(13);
|
||||
us.insert(9);
|
||||
us.insert(8);
|
||||
us.insert(10);
|
||||
us.insert(7);
|
||||
us.insert(12);
|
||||
std::cout << "us 的 bucket 数量是: " << us.bucket_count()
|
||||
<< "\tus 的 负载因子 是: " << us.load_factor() << std::endl;
|
||||
|
||||
// 会去重,但是不会自动排序
|
||||
std::unordered_set<int>::iterator it = us.begin();
|
||||
while (it != us.end())
|
||||
{
|
||||
std::cout << *it << " ";
|
||||
++it;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
std::set<int> s; // Java里面取名叫TreeSet
|
||||
s.insert(4);
|
||||
s.insert(2);
|
||||
s.insert(1);
|
||||
s.insert(5);
|
||||
s.insert(6);
|
||||
s.insert(3);
|
||||
s.insert(5);
|
||||
s.insert(6);
|
||||
s.insert(3);
|
||||
s.insert(15);
|
||||
s.insert(16);
|
||||
s.insert(13);
|
||||
s.insert(15);
|
||||
s.insert(16);
|
||||
s.insert(13);
|
||||
s.insert(9);
|
||||
s.insert(8);
|
||||
s.insert(10);
|
||||
s.insert(7);
|
||||
s.insert(12);
|
||||
// set会去重,会自动排序
|
||||
std::set<int>::iterator its = s.begin();
|
||||
while (its != s.end())
|
||||
{
|
||||
std::cout << *its << " ";
|
||||
++its;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
void Test_unordered_map()
|
||||
{
|
||||
std::unordered_map<std::string, std::string> dict;
|
||||
dict.insert(std::make_pair("hello", "你好"));
|
||||
dict.insert(std::make_pair("world", "世界"));
|
||||
dict.insert(std::make_pair("apple", "苹果"));
|
||||
dict.insert(std::make_pair("orange", "橘子"));
|
||||
dict.insert(std::make_pair("banana", "香蕉"));
|
||||
dict.insert(std::make_pair("peach", "桃子"));
|
||||
dict.insert(std::make_pair("peach", "桃子"));
|
||||
dict.insert(std::make_pair("peach", "桃子"));
|
||||
|
||||
dict.insert(std::make_pair("sort", "排序"));
|
||||
dict["string"] = "字符串";
|
||||
|
||||
std::unordered_map<std::string, std::string>::iterator it = dict.begin();
|
||||
while (it != dict.end())
|
||||
{
|
||||
std::cout << it->first << " " << it->second << std::endl;
|
||||
++it;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
std::map<std::string, std::string> mdict;
|
||||
mdict.insert(std::make_pair("hello", "你好"));
|
||||
mdict.insert(std::make_pair("world", "世界"));
|
||||
mdict.insert(std::make_pair("apple", "苹果"));
|
||||
mdict.insert(std::make_pair("orange", "橘子"));
|
||||
mdict.insert(std::make_pair("banana", "香蕉"));
|
||||
mdict.insert(std::make_pair("peach", "桃子"));
|
||||
mdict.insert(std::make_pair("peach", "桃子"));
|
||||
mdict.insert(std::make_pair("peach", "桃子"));
|
||||
|
||||
mdict.insert(std::make_pair("sort", "排序"));
|
||||
mdict["string"] = "字符串";
|
||||
|
||||
std::map<std::string, std::string>::iterator mit = mdict.begin();
|
||||
while (mit != mdict.end())
|
||||
{
|
||||
std::cout << mit->first << " " << mit->second << std::endl;
|
||||
++mit;
|
||||
}
|
||||
}
|
||||
|
||||
void Test_OP()
|
||||
{
|
||||
std::unordered_set<int> us;
|
||||
std::set<int> s;
|
||||
|
||||
const size_t n = 100000;
|
||||
std::vector<int> v;
|
||||
v.reserve(n); // reserve()函数是vector预留空间的,但是并不真正创建元素对象。
|
||||
// resize()函数是开空间+初始化
|
||||
srand(time(0));
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
v.push_back(rand());
|
||||
}
|
||||
|
||||
// 插入
|
||||
clock_t begin = clock();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
us.insert(v[i]);
|
||||
}
|
||||
clock_t end = clock();
|
||||
std::cout << "unordered_set insert time:\t" << end - begin << std::endl;
|
||||
|
||||
begin = clock();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
s.insert(v[i]);
|
||||
}
|
||||
end = clock();
|
||||
std::cout << "set insert time:\t\t" << end - begin << std::endl;
|
||||
|
||||
// 查找
|
||||
begin = clock();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
us.find(v[i]);
|
||||
}
|
||||
end = clock();
|
||||
std::cout << "unordered_set find time:\t" << end - begin << std::endl;
|
||||
|
||||
begin = clock();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
s.find(v[i]);
|
||||
}
|
||||
end = clock();
|
||||
std::cout << "set find time:\t\t\t" << end - begin << std::endl;
|
||||
|
||||
// 删除
|
||||
begin = clock();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
us.erase(v[i]);
|
||||
}
|
||||
end = clock();
|
||||
std::cout << "unordered_set erase time:\t" << end - begin << std::endl;
|
||||
|
||||
begin = clock();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
s.erase(v[i]);
|
||||
}
|
||||
end = clock();
|
||||
std::cout << "set erase time:\t\t\t" << end - begin << std::endl;
|
||||
}
|
||||
|
||||
void Test_Close_HashTable()
|
||||
{
|
||||
Lenyiin::Close_HashTable<int, int, Lenyiin::SetKeyOfT<int>> ht;
|
||||
ht.Insert(4);
|
||||
ht.Insert(14);
|
||||
ht.Insert(24);
|
||||
ht.Insert(5);
|
||||
ht.Insert(15);
|
||||
ht.Insert(25);
|
||||
ht.Insert(6);
|
||||
ht.Insert(16);
|
||||
|
||||
ht.Print();
|
||||
|
||||
ht.Erase(14);
|
||||
ht.Erase(24);
|
||||
ht.Print();
|
||||
|
||||
std::cout << "是否存在 5 ? " << (ht.Find(5) ? "true" : "false") << std::endl;
|
||||
}
|
||||
|
||||
void Test_Open_HashTable_1()
|
||||
{
|
||||
Lenyiin::Open_HashTable<int, int, Lenyiin::SetKeyOfT<int>, Lenyiin::_Hash<int>> ht;
|
||||
ht.Insert(4);
|
||||
ht.Insert(14);
|
||||
ht.Insert(24);
|
||||
ht.Insert(5);
|
||||
ht.Insert(15);
|
||||
ht.Insert(25);
|
||||
ht.Insert(6);
|
||||
ht.Insert(16);
|
||||
ht.Insert(26);
|
||||
ht.Insert(36);
|
||||
ht.Insert(33);
|
||||
ht.Insert(37);
|
||||
ht.Insert(32);
|
||||
|
||||
ht.Print();
|
||||
|
||||
ht.Erase(4);
|
||||
ht.Erase(14);
|
||||
|
||||
ht.Print();
|
||||
}
|
||||
|
||||
void Test_Open_HashTable_2()
|
||||
{
|
||||
Lenyiin::Open_HashTable<std::string, std::string, Lenyiin::SetKeyOfT<std::string>, Lenyiin::_Hash<std::string>> ht;
|
||||
ht.Insert("sort");
|
||||
ht.Insert("string");
|
||||
ht.Insert("left");
|
||||
ht.Insert("right");
|
||||
|
||||
std::cout << ht.HashFunc("abcd") << std::endl;
|
||||
std::cout << ht.HashFunc("aadd") << std::endl;
|
||||
}
|
||||
|
||||
void Test_Unordered_Set()
|
||||
{
|
||||
Lenyiin::Unordered_Set<int> s;
|
||||
s.Insert(1);
|
||||
s.Insert(5);
|
||||
s.Insert(4);
|
||||
s.Insert(2);
|
||||
s.Insert(5);
|
||||
s.Insert(5);
|
||||
s.Insert(53);
|
||||
s.Insert(54);
|
||||
|
||||
Lenyiin::Unordered_Set<int>::iterator it = s.begin();
|
||||
while (it != s.end())
|
||||
{
|
||||
std::cout << *it << " ";
|
||||
++it;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
s.Print();
|
||||
|
||||
std::cout << "查找 4: " << (s.Find(4) ? "true" : "false") << std::endl;
|
||||
std::cout << "查找 6: " << (s.Find(6) ? "true" : "false") << std::endl;
|
||||
|
||||
std::cout << "删除 2" << std::endl;
|
||||
s.Erase(2);
|
||||
s.Print();
|
||||
}
|
||||
|
||||
void Test_Unordered_Map()
|
||||
{
|
||||
Lenyiin::Unordered_Map<std::string, std::string> dict;
|
||||
dict.Insert(std::make_pair("sort", "排序"));
|
||||
dict.Insert(std::make_pair("left", "左边"));
|
||||
dict.Insert(std::make_pair("string", "字符串"));
|
||||
|
||||
dict["left"] = "剩余"; // 修改
|
||||
dict["end"] = "尾部"; // 插入 + 修改
|
||||
|
||||
// Unordered_Map<string, string>::iterator it = dict.begin();
|
||||
auto it = dict.begin();
|
||||
while (it != dict.end())
|
||||
{
|
||||
// cout << it->first << ":" << it->second << endl;
|
||||
std::cout << (*it).first << ":" << (*it).second << std::endl;
|
||||
++it;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
dict.Print();
|
||||
|
||||
std::cout << "查找 left: " << (dict.Find("left") ? "true" : "false") << std::endl;
|
||||
std::cout << "查找 up: " << (dict.Find("up") ? "true" : "false") << std::endl;
|
||||
|
||||
std::cout << "删除 left" << std::endl;
|
||||
dict.Erase("left");
|
||||
dict.Print();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Test_unordered_set();
|
||||
// Test_unordered_map();
|
||||
// Test_OP();
|
||||
|
||||
// Test_Close_HashTable();
|
||||
// Test_Open_HashTable_1();
|
||||
// Test_Open_HashTable_2();
|
||||
|
||||
// Test_Unordered_Set();
|
||||
Test_Unordered_Map();
|
||||
|
||||
return 0;
|
||||
}
|
6
Linux/Makefile
Normal file
6
Linux/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
main:Main.cc
|
||||
g++ -o $@ $^
|
||||
|
||||
.PHONY:clean
|
||||
clean:
|
||||
rm -f main
|
74
Linux/Unordered_Map.hpp
Normal file
74
Linux/Unordered_Map.hpp
Normal file
@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include "HashTable.hpp"
|
||||
|
||||
namespace Lenyiin
|
||||
{
|
||||
template <class K, class V, class Hash = _Hash<K>>
|
||||
class Unordered_Map
|
||||
{
|
||||
public:
|
||||
struct MapKOfT
|
||||
{
|
||||
const K &operator()(const std::pair<K, V> &kv)
|
||||
{
|
||||
return kv.first;
|
||||
}
|
||||
};
|
||||
|
||||
typedef typename Open_HashTable<K, std::pair<K, V>, MapKOfT, Hash>::iterator iterator;
|
||||
|
||||
iterator begin()
|
||||
{
|
||||
return _hashTable.begin();
|
||||
}
|
||||
|
||||
iterator end()
|
||||
{
|
||||
return _hashTable.end();
|
||||
}
|
||||
|
||||
// 构造函数: 指定哈希表的初始大小
|
||||
Unordered_Map(size_t bucket_count = 10)
|
||||
: _hashTable(bucket_count)
|
||||
{
|
||||
}
|
||||
|
||||
// 析构
|
||||
~Unordered_Map()
|
||||
{
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> Insert(const std::pair<K, V> &kv)
|
||||
{
|
||||
return _hashTable.Insert(kv);
|
||||
}
|
||||
|
||||
V &operator[](const K &key)
|
||||
{
|
||||
std::pair<iterator, bool> ret = _hashTable.Insert(std::make_pair(key, V()));
|
||||
return ret.first->second;
|
||||
}
|
||||
|
||||
// 查找元素
|
||||
bool Find(const K &key)
|
||||
{
|
||||
return _hashTable.Find(key);
|
||||
}
|
||||
|
||||
// 删除元素
|
||||
bool Erase(const K &key)
|
||||
{
|
||||
return _hashTable.Erase(key);
|
||||
}
|
||||
|
||||
// 打印
|
||||
void Print() const
|
||||
{
|
||||
_hashTable.Print();
|
||||
}
|
||||
|
||||
private:
|
||||
Open_HashTable<K, std::pair<K, V>, MapKOfT, Hash> _hashTable;
|
||||
};
|
||||
}
|
70
Linux/Unordered_Set.hpp
Normal file
70
Linux/Unordered_Set.hpp
Normal file
@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include "HashTable.hpp"
|
||||
|
||||
namespace Lenyiin
|
||||
{
|
||||
template <class K, class Hash = _Hash<K>>
|
||||
class Unordered_Set
|
||||
{
|
||||
public:
|
||||
struct SetKOfT
|
||||
{
|
||||
const K &operator()(const K &key)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
};
|
||||
|
||||
typedef typename Open_HashTable<K, K, SetKOfT, Hash>::iterator iterator;
|
||||
|
||||
iterator begin()
|
||||
{
|
||||
return _hashTable.begin();
|
||||
}
|
||||
|
||||
iterator end()
|
||||
{
|
||||
return _hashTable.end();
|
||||
}
|
||||
|
||||
// 构造函数: 指定哈希表的初始大小
|
||||
Unordered_Set(size_t bucket_count = 10)
|
||||
: _hashTable(bucket_count)
|
||||
{
|
||||
}
|
||||
|
||||
// 析构
|
||||
~Unordered_Set()
|
||||
{
|
||||
}
|
||||
|
||||
// 插入元素
|
||||
std::pair<iterator, bool> Insert(const K &key)
|
||||
{
|
||||
return _hashTable.Insert(key);
|
||||
}
|
||||
|
||||
// 查找元素
|
||||
bool Find(const K &key)
|
||||
{
|
||||
return _hashTable.Find(key);
|
||||
}
|
||||
|
||||
// 删除元素
|
||||
bool Erase(const K &key)
|
||||
{
|
||||
return _hashTable.Erase(key);
|
||||
}
|
||||
|
||||
// 打印
|
||||
void Print() const
|
||||
{
|
||||
_hashTable.Print();
|
||||
}
|
||||
|
||||
private:
|
||||
// 使用哈希表作为底层数据结构
|
||||
Open_HashTable<K, K, SetKOfT, Hash> _hashTable;
|
||||
};
|
||||
}
|
BIN
Linux/main
Normal file
BIN
Linux/main
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Windows_Unordered_Set_Map/.vs/Windows_Unordered_Set_Map/v17/.suo
Normal file
BIN
Windows_Unordered_Set_Map/.vs/Windows_Unordered_Set_Map/v17/.suo
Normal file
Binary file not shown.
Binary file not shown.
@ -0,0 +1,100 @@
|
||||
{
|
||||
"Version": 1,
|
||||
"WorkspaceRootPath": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\",
|
||||
"Documents": [
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}|Windows_Unordered_Set_Map.vcxproj|E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\Main.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||
"RelativeMoniker": "D:0:0:{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}|Windows_Unordered_Set_Map.vcxproj|solutionrelative:Main.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}|Windows_Unordered_Set_Map.vcxproj|E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\HashTable.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||
"RelativeMoniker": "D:0:0:{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}|Windows_Unordered_Set_Map.vcxproj|solutionrelative:HashTable.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}|Windows_Unordered_Set_Map.vcxproj|E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\Unordered_Set.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||
"RelativeMoniker": "D:0:0:{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}|Windows_Unordered_Set_Map.vcxproj|solutionrelative:Unordered_Set.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}|Windows_Unordered_Set_Map.vcxproj|E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\Unordered_Map.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||
"RelativeMoniker": "D:0:0:{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}|Windows_Unordered_Set_Map.vcxproj|solutionrelative:Unordered_Map.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||
}
|
||||
],
|
||||
"DocumentGroupContainers": [
|
||||
{
|
||||
"Orientation": 0,
|
||||
"VerticalTabListWidth": 256,
|
||||
"DocumentGroups": [
|
||||
{
|
||||
"DockedWidth": 267,
|
||||
"SelectedChildIndex": 3,
|
||||
"Children": [
|
||||
{
|
||||
"$type": "Bookmark",
|
||||
"Name": "ST:128:0:{116d2292-e37d-41cd-a077-ebacac4c8cc4}"
|
||||
},
|
||||
{
|
||||
"$type": "Bookmark",
|
||||
"Name": "ST:129:0:{116d2292-e37d-41cd-a077-ebacac4c8cc4}"
|
||||
},
|
||||
{
|
||||
"$type": "Bookmark",
|
||||
"Name": "ST:128:0:{1fc202d4-d401-403c-9834-5b218574bb67}"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 0,
|
||||
"Title": "Main.cpp",
|
||||
"DocumentMoniker": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\Main.cpp",
|
||||
"RelativeDocumentMoniker": "Main.cpp",
|
||||
"ToolTip": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\Main.cpp*",
|
||||
"RelativeToolTip": "Main.cpp*",
|
||||
"ViewState": "AgIAACwBAAAAAAAAAAAowDcBAAAZAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|",
|
||||
"WhenOpened": "2024-09-27T15:45:08.801Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 3,
|
||||
"Title": "Unordered_Map.hpp",
|
||||
"DocumentMoniker": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\Unordered_Map.hpp",
|
||||
"RelativeDocumentMoniker": "Unordered_Map.hpp",
|
||||
"ToolTip": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\Unordered_Map.hpp",
|
||||
"RelativeToolTip": "Unordered_Map.hpp",
|
||||
"ViewState": "AgIAACAAAAAAAAAAAAAowEkAAAABAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||
"WhenOpened": "2024-09-27T15:44:59.73Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 2,
|
||||
"Title": "Unordered_Set.hpp",
|
||||
"DocumentMoniker": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\Unordered_Set.hpp",
|
||||
"RelativeDocumentMoniker": "Unordered_Set.hpp",
|
||||
"ToolTip": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\Unordered_Set.hpp",
|
||||
"RelativeToolTip": "Unordered_Set.hpp",
|
||||
"ViewState": "AgIAABwAAAAAAAAAAAAowCAAAAAmAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||
"WhenOpened": "2024-09-27T15:44:46.521Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 1,
|
||||
"Title": "HashTable.hpp",
|
||||
"DocumentMoniker": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\HashTable.hpp",
|
||||
"RelativeDocumentMoniker": "HashTable.hpp",
|
||||
"ToolTip": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\HashTable.hpp",
|
||||
"RelativeToolTip": "HashTable.hpp",
|
||||
"ViewState": "AgIAAIACAAAAAAAAAAAowKwCAAABAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||
"WhenOpened": "2024-09-27T15:44:25.257Z",
|
||||
"EditorCaption": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
{
|
||||
"Version": 1,
|
||||
"WorkspaceRootPath": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\",
|
||||
"Documents": [
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}|Windows_Unordered_Set_Map.vcxproj|E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\Main.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||
"RelativeMoniker": "D:0:0:{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}|Windows_Unordered_Set_Map.vcxproj|solutionrelative:Main.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}|Windows_Unordered_Set_Map.vcxproj|E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\HashTable.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||
"RelativeMoniker": "D:0:0:{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}|Windows_Unordered_Set_Map.vcxproj|solutionrelative:HashTable.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}|Windows_Unordered_Set_Map.vcxproj|E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\Unordered_Set.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||
"RelativeMoniker": "D:0:0:{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}|Windows_Unordered_Set_Map.vcxproj|solutionrelative:Unordered_Set.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}|Windows_Unordered_Set_Map.vcxproj|E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\Unordered_Map.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||
"RelativeMoniker": "D:0:0:{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}|Windows_Unordered_Set_Map.vcxproj|solutionrelative:Unordered_Map.hpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||
}
|
||||
],
|
||||
"DocumentGroupContainers": [
|
||||
{
|
||||
"Orientation": 0,
|
||||
"VerticalTabListWidth": 256,
|
||||
"DocumentGroups": [
|
||||
{
|
||||
"DockedWidth": 267,
|
||||
"SelectedChildIndex": 3,
|
||||
"Children": [
|
||||
{
|
||||
"$type": "Bookmark",
|
||||
"Name": "ST:128:0:{116d2292-e37d-41cd-a077-ebacac4c8cc4}"
|
||||
},
|
||||
{
|
||||
"$type": "Bookmark",
|
||||
"Name": "ST:129:0:{116d2292-e37d-41cd-a077-ebacac4c8cc4}"
|
||||
},
|
||||
{
|
||||
"$type": "Bookmark",
|
||||
"Name": "ST:128:0:{1fc202d4-d401-403c-9834-5b218574bb67}"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 0,
|
||||
"Title": "Main.cpp",
|
||||
"DocumentMoniker": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\Main.cpp",
|
||||
"RelativeDocumentMoniker": "Main.cpp",
|
||||
"ToolTip": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\Main.cpp",
|
||||
"RelativeToolTip": "Main.cpp",
|
||||
"ViewState": "AgIAAPAAAAAAAAAAAAAowP8AAAAQAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|",
|
||||
"WhenOpened": "2024-09-27T15:45:08.801Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 3,
|
||||
"Title": "Unordered_Map.hpp",
|
||||
"DocumentMoniker": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\Unordered_Map.hpp",
|
||||
"RelativeDocumentMoniker": "Unordered_Map.hpp",
|
||||
"ToolTip": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\Unordered_Map.hpp",
|
||||
"RelativeToolTip": "Unordered_Map.hpp",
|
||||
"ViewState": "AgIAACAAAAAAAAAAAAAowEkAAAABAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||
"WhenOpened": "2024-09-27T15:44:59.73Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 2,
|
||||
"Title": "Unordered_Set.hpp",
|
||||
"DocumentMoniker": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\Unordered_Set.hpp",
|
||||
"RelativeDocumentMoniker": "Unordered_Set.hpp",
|
||||
"ToolTip": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\Unordered_Set.hpp",
|
||||
"RelativeToolTip": "Unordered_Set.hpp",
|
||||
"ViewState": "AgIAABwAAAAAAAAAAAAowCAAAAAmAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||
"WhenOpened": "2024-09-27T15:44:46.521Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 1,
|
||||
"Title": "HashTable.hpp",
|
||||
"DocumentMoniker": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\HashTable.hpp",
|
||||
"RelativeDocumentMoniker": "HashTable.hpp",
|
||||
"ToolTip": "E:\\Git \u4ED3\u5E93\\\u516C\u5F00\u4ED3\u5E93\\10_unordered-set-map\\Windows_Unordered_Set_Map\\HashTable.hpp",
|
||||
"RelativeToolTip": "HashTable.hpp",
|
||||
"ViewState": "AgIAAIACAAAAAAAAAAAowKwCAAABAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||
"WhenOpened": "2024-09-27T15:44:25.257Z",
|
||||
"EditorCaption": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
Binary file not shown.
Binary file not shown.
685
Windows_Unordered_Set_Map/HashTable.hpp
Normal file
685
Windows_Unordered_Set_Map/HashTable.hpp
Normal file
@ -0,0 +1,685 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
// unordered_set<K> -> HashTable<K, K>
|
||||
// unordered_map<K, V> -> HashTable<K, pair<K, V>>
|
||||
|
||||
namespace Lenyiin
|
||||
{
|
||||
template <class K>
|
||||
struct SetKeyOfT
|
||||
{
|
||||
const K& operator()(const K& key)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
};
|
||||
|
||||
enum State
|
||||
{
|
||||
EMPTY, // 槽位为空
|
||||
EXIST, // 槽位已经存在一个元素
|
||||
DELETE // 槽位中元素被删除
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct HashData
|
||||
{
|
||||
T _data;
|
||||
State _state;
|
||||
|
||||
HashData()
|
||||
: _data(T()), _state(EMPTY)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <class K, class T, class KeyOfT>
|
||||
class Close_HashTable
|
||||
{
|
||||
private:
|
||||
typedef struct HashData<T> HashData;
|
||||
|
||||
size_t SecondHash(const K& key, size_t table_size)
|
||||
{
|
||||
return 1 + (key % (table_size - 1));
|
||||
}
|
||||
|
||||
public:
|
||||
// 负载因子 = 表中数据/表的大小 衡量哈希表满的程度
|
||||
// 表越接近满, 插入数据越容易冲突, 冲突越多, 效率越低
|
||||
// 哈希表并不是满了才增容, 开放定制法中, 一般负载因子到 0.7 左右就开始增容
|
||||
// 负载因子越小, 冲突概率越低, 整体效率越高, 但是负载因子越小, 浪费的空间越大, 所以负载因子一般取一个折中的值
|
||||
void CheckCapacity()
|
||||
{
|
||||
KeyOfT koft;
|
||||
|
||||
// // version 1
|
||||
// if (_tables.size() == 0 || _num * 10 / _tables.size() >= 7)
|
||||
// {
|
||||
// // 增容
|
||||
// // 1. 开 2倍大小的新表
|
||||
// // 2. 遍历旧表的数据,重新计算在新表中位置
|
||||
// // 3. 释放旧表
|
||||
// std::vector<HashData> newtables;
|
||||
// size_t newsize = _tables.size() == 0 ? 10 : _tables.size() * 2;
|
||||
// newtables.resize(newsize);
|
||||
// for (size_t i = 0; i < _tables.size(); i++)
|
||||
// {
|
||||
// if (_tables[i]._state == EXIST)
|
||||
// {
|
||||
// // 计算在新表中的位置, 并处理冲突
|
||||
// size_t index = koft(_tables[i]._data) % newtables.size();
|
||||
// while (newtables[index]._state == EXIST)
|
||||
// {
|
||||
// ++index;
|
||||
// if (index == _tables.size())
|
||||
// {
|
||||
// index = 0;
|
||||
// }
|
||||
// }
|
||||
// newtables[index] = _tables[i];
|
||||
// }
|
||||
// }
|
||||
// _tables.swap(newtables);
|
||||
// }
|
||||
|
||||
// // version 2
|
||||
// if (_tables.size() == 0 || _num * 10 / _tables.size() >= 7)
|
||||
// {
|
||||
// // 增容
|
||||
// // 1. 开 2倍大小的新表
|
||||
// // 2. 遍历旧表的数据,重新计算在新表中位置
|
||||
// // 3. 释放旧表
|
||||
// std::vector<HashData> newtables;
|
||||
// size_t newsize = _tables.size() == 0 ? 10 : _tables.size() * 2;
|
||||
// newtables.resize(newsize);
|
||||
// for (size_t i = 0; i < _tables.size(); i++)
|
||||
// {
|
||||
// if (_tables[i]._state == EXIST)
|
||||
// {
|
||||
// // 重新计算新表中的位置
|
||||
// size_t index = koft(_tables[i]._data) % newtables.size();
|
||||
// size_t step = SecondHash(koft(_tables[i]._data), newtables.size());
|
||||
|
||||
// // 处理冲突:双重哈希探测
|
||||
// while (newtables[index]._state == EXIST)
|
||||
// {
|
||||
// index = (index + step) % newtables.size();
|
||||
// }
|
||||
|
||||
// // 插入元素到新表
|
||||
// newtables[index] = _tables[i];
|
||||
// }
|
||||
// }
|
||||
// _tables.swap(newtables);
|
||||
// }
|
||||
|
||||
// version 3
|
||||
// 另一种增容思路
|
||||
if (_tables.size() == 0 || _num * 10 / _tables.size() >= 7)
|
||||
{
|
||||
Close_HashTable<K, T, KeyOfT> newht;
|
||||
size_t newsize = _tables.size() == 0 ? 10 : _tables.size() * 2;
|
||||
newht._tables.resize(newsize);
|
||||
for (size_t i = 0; i < _tables.size(); i++)
|
||||
{
|
||||
if (_tables[i]._state == EXIST)
|
||||
{
|
||||
newht.Insert(_tables[i]._data);
|
||||
}
|
||||
}
|
||||
_tables.swap(newht._tables);
|
||||
}
|
||||
}
|
||||
|
||||
bool Insert(const T& data)
|
||||
{
|
||||
KeyOfT koft;
|
||||
|
||||
CheckCapacity();
|
||||
// 闭散列中线性探测有什么问题?
|
||||
// 线性探测思路就是我的位置被占了, 我就挨着往后去占别人的位置, 可能会导致一片一片的冲突, 洪水效应
|
||||
|
||||
// version 1
|
||||
// 线性探测
|
||||
// 计算 data 中的 key 在表中映射的位置
|
||||
// size_t index = koft(data) % _tables.size();
|
||||
// while (_tables[index]._state == EXIST)
|
||||
// {
|
||||
// if (koft(_tables[index]._data) == koft(data))
|
||||
// {
|
||||
// return false; // 已经存在
|
||||
// }
|
||||
// ++index;
|
||||
// if (index == _tables.size())
|
||||
// {
|
||||
// index = 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
// version 2
|
||||
// 二次探测
|
||||
// 计算 data 中的 key 在表中映射的位置
|
||||
// size_t start = koft(data) % _tables.size();
|
||||
// size_t index = start;
|
||||
// int i = 0;
|
||||
// while (_tables[index]._state == EXIST)
|
||||
// {
|
||||
// if (koft(_tables[index]._data) == koft(data))
|
||||
// {
|
||||
// return false; // 已经存在
|
||||
// }
|
||||
// index = start + i * i;
|
||||
// i++;
|
||||
// index %= _tables.size();
|
||||
// }
|
||||
|
||||
// version 3
|
||||
// 双重哈希
|
||||
size_t index = koft(data) % _tables.size();
|
||||
size_t step = SecondHash(koft(data), _tables.size());
|
||||
while (_tables[index]._state == EXIST)
|
||||
{
|
||||
if (koft(_tables[index]._data) == koft(data))
|
||||
{
|
||||
return false; // 如果找到相同的 key,插入失败
|
||||
}
|
||||
|
||||
index = (index + step) % _tables.size(); // 使用双重哈希计算下一个位置
|
||||
}
|
||||
|
||||
_tables[index]._data = data;
|
||||
_tables[index]._state = EXIST;
|
||||
++_num;
|
||||
|
||||
// 我么可以看到闭散列-开放定制法不是一种好的解决方式, 因为它是一种我的位置被占了, 我就去抢占别人的位置的思路
|
||||
// 也就是说他的哈希冲突会相互影响, 我冲突占你的, 你冲突占他的, 他冲突了... , 没完没了, 整体的效率都变低了
|
||||
// 开散列的哈希桶可以解决上面的问题
|
||||
return true;
|
||||
}
|
||||
|
||||
// 线性探测
|
||||
// HashData *Find(const K &key)
|
||||
// {
|
||||
// KeyOfT koft;
|
||||
// // 计算 data 中的 key 在表中映射的位置
|
||||
// size_t index = key % _tables.size();
|
||||
// while (_tables[index]._state != EMPTY)
|
||||
// {
|
||||
// if (koft(_tables[index]._data) == key)
|
||||
// {
|
||||
// if (_tables[index]._state == EXIST)
|
||||
// {
|
||||
// return &_tables[index];
|
||||
// }
|
||||
// else if (_tables[index]._state == DELETE)
|
||||
// {
|
||||
// return nullptr;
|
||||
// }
|
||||
// }
|
||||
// ++index;
|
||||
// if (index == _tables.size())
|
||||
// {
|
||||
// index = 0;
|
||||
// }
|
||||
// }
|
||||
// return nullptr;
|
||||
// }
|
||||
|
||||
// 双重哈希
|
||||
HashData* Find(const K& key)
|
||||
{
|
||||
KeyOfT koft;
|
||||
size_t index = key % _tables.size();
|
||||
size_t step = SecondHash(key, _tables.size()); // 计算步长
|
||||
while (_tables[index]._state != EMPTY)
|
||||
{
|
||||
if (koft(_tables[index]._data) == key)
|
||||
{
|
||||
if (_tables[index]._state == EXIST)
|
||||
{
|
||||
return &_tables[index];
|
||||
}
|
||||
else if (_tables[index]._state == DELETE)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
index = (index + step) % _tables.size(); // 使用双重哈希探测下一个位置
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Erase(const K& key)
|
||||
{
|
||||
HashData* ret = Find(key);
|
||||
if (ret)
|
||||
{
|
||||
ret->_state = DELETE;
|
||||
--_num;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
HashData& getHashData(int pos)
|
||||
{
|
||||
return _tables[pos];
|
||||
}
|
||||
|
||||
void Print()
|
||||
{
|
||||
int size = _tables.size();
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
std::cout << i << "\t";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
auto cur = _tables[i];
|
||||
if (cur._state == EXIST)
|
||||
{
|
||||
std::cout << cur._data << "\t";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "*\t";
|
||||
}
|
||||
}
|
||||
std::cout << "\n\n";
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<HashData> _tables;
|
||||
size_t _num = 0; // 存储了几个有效数据
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct HashNode
|
||||
{
|
||||
T _data; // 存储数据
|
||||
HashNode<T>* _next; // 存储下一个节点
|
||||
|
||||
// 如果想要实现迭代顺序为插入顺序, 可以加两个指针组成一个链表
|
||||
// HashNode<T>* _linknext;
|
||||
// HashNode<T>* _linkprev;
|
||||
|
||||
HashNode(const T& data)
|
||||
: _data(data), _next(nullptr)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// 前置声明
|
||||
template <class K, class T, class KeyOfT, class Hash>
|
||||
class Open_HashTable;
|
||||
|
||||
// 哈希表只有单向迭代器, 只有 ++, 没有--
|
||||
template <class K, class T, class KeyOfT, class Hash>
|
||||
struct __HashTableIterator
|
||||
{
|
||||
typedef __HashTableIterator<K, T, KeyOfT, Hash> Self;
|
||||
typedef Open_HashTable<K, T, KeyOfT, Hash> HT;
|
||||
typedef HashNode<T> 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 index = _pht->HashFunc(koft(_node->_data)) % _pht->_tables.size();
|
||||
++index;
|
||||
while (index < _pht->_tables.size())
|
||||
{
|
||||
Node* cur = _pht->_tables[index];
|
||||
if (cur)
|
||||
{
|
||||
_node = cur;
|
||||
return *this;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
_node = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Self operator++(int)
|
||||
{
|
||||
Self tmp(*this);
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator!=(const Self& s)
|
||||
{
|
||||
return _node != s._node;
|
||||
}
|
||||
|
||||
bool operator==(const Self& s)
|
||||
{
|
||||
return _node == s._node;
|
||||
}
|
||||
};
|
||||
|
||||
template <class K>
|
||||
struct _Hash
|
||||
{
|
||||
const K& operator()(const K& key)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
};
|
||||
|
||||
// 特化
|
||||
template <>
|
||||
struct _Hash<std::string>
|
||||
{
|
||||
size_t operator()(const std::string& key)
|
||||
{
|
||||
// BKDR Hash
|
||||
size_t hash = 0;
|
||||
for (size_t i = 0; i < key.size(); i++)
|
||||
{
|
||||
hash *= 131;
|
||||
hash += key[i];
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
struct _HashString
|
||||
{
|
||||
size_t operator()(const std::string& key)
|
||||
{
|
||||
// BKDR Hash
|
||||
size_t hash = 0;
|
||||
for (size_t i = 0; i < key.size(); i++)
|
||||
{
|
||||
hash *= 131;
|
||||
hash += key[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
template <class K, class T, class KeyOfT, class Hash>
|
||||
// template <class K, class T, class KeyOfT, class Hash = _Hash<K>>
|
||||
class Open_HashTable
|
||||
{
|
||||
private:
|
||||
typedef HashNode<T> Node;
|
||||
|
||||
public:
|
||||
friend struct __HashTableIterator<K, T, KeyOfT, Hash>;
|
||||
typedef __HashTableIterator<K, T, KeyOfT, Hash> iterator;
|
||||
|
||||
iterator begin()
|
||||
{
|
||||
for (size_t i = 0; i < _tables.size(); i++)
|
||||
{
|
||||
if (_tables[i])
|
||||
{
|
||||
return iterator(_tables[i], this);
|
||||
}
|
||||
}
|
||||
return end();
|
||||
}
|
||||
|
||||
iterator end()
|
||||
{
|
||||
return iterator(nullptr, this);
|
||||
}
|
||||
|
||||
Open_HashTable()
|
||||
{
|
||||
}
|
||||
|
||||
Open_HashTable(size_t bucket_count)
|
||||
: _tables(bucket_count), _num(0)
|
||||
{
|
||||
}
|
||||
|
||||
~Open_HashTable()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
for (size_t i = 0; i < _tables.size(); i++)
|
||||
{
|
||||
Node* cur = _tables[i];
|
||||
while (cur)
|
||||
{
|
||||
Node* next = cur->_next;
|
||||
delete cur;
|
||||
cur = next;
|
||||
}
|
||||
_tables[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
size_t HashFunc(const K& key)
|
||||
{
|
||||
Hash hash;
|
||||
return hash(key);
|
||||
}
|
||||
|
||||
size_t GetNextPrime(size_t num)
|
||||
{
|
||||
const int PrimeSize = 28;
|
||||
static const unsigned long PrimeList[PrimeSize] =
|
||||
{
|
||||
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 < PrimeSize; i++)
|
||||
{
|
||||
if (PrimeList[i] > num)
|
||||
{
|
||||
return PrimeList[i];
|
||||
}
|
||||
}
|
||||
|
||||
return PrimeList[PrimeSize - 1]; // 如果已经是最后一个数的, 则不增容
|
||||
}
|
||||
|
||||
// 重新哈希
|
||||
void Rehash(size_t newsize)
|
||||
{
|
||||
KeyOfT koft;
|
||||
std::vector<Node*> newtables;
|
||||
newtables.resize(newsize);
|
||||
for (size_t i = 0; i < _tables.size(); i++)
|
||||
{
|
||||
// 将旧表中的节点取下来, 重新计算在新表中的位置, 并插入进去
|
||||
Node* cur = _tables[i];
|
||||
while (cur)
|
||||
{
|
||||
Node* next = cur->_next;
|
||||
size_t index = HashFunc(koft(cur->_data)) % newtables.size();
|
||||
cur->_next = newtables[index];
|
||||
newtables[index] = cur;
|
||||
cur = next;
|
||||
}
|
||||
_tables[i] = nullptr;
|
||||
}
|
||||
_tables.swap(newtables);
|
||||
}
|
||||
|
||||
// 插入操作
|
||||
// 当大量的数据冲突, 这些哈希冲突的数据就会挂在同一个链式桶中, 查找时效率就会降低, 所以开散列-哈希桶也是要控制哈希冲突的。
|
||||
// 如何控制呢? 通过控制负载因子, 不过这里就把空间利用率提高一些, 负载因子也可以高一些, 一般开散列把负载因子控制到1, 会比较好一点
|
||||
std::pair<iterator, bool> Insert(const T& data)
|
||||
{
|
||||
KeyOfT koft;
|
||||
|
||||
// 1. 检查负载因子
|
||||
// 如果负载因子等于 1 , 则增容, 避免大量的哈希冲突
|
||||
if (_tables.size() == _num)
|
||||
{
|
||||
// 1. 开两倍大小的新表(不一定是两倍)
|
||||
// 2. 遍历旧表的数据, 重新计算在新表中的位置
|
||||
// 3. 释放旧表
|
||||
size_t newsize = _tables.size() == 0 ? 10 : _tables.size() * 2;
|
||||
// size_t newsize = GetNextPrime(_tables.size());
|
||||
|
||||
Rehash(newsize);
|
||||
}
|
||||
|
||||
// 2. 计算数据在表中映射的位置
|
||||
size_t index = HashFunc(koft(data)) % _tables.size();
|
||||
|
||||
// 3. 先查找这个值在不在表中, 是否有冲突
|
||||
Node* cur = _tables[index];
|
||||
while (cur)
|
||||
{
|
||||
if (HashFunc(koft(cur->_data)) == HashFunc(koft(data)))
|
||||
{
|
||||
// 如果已经存在该键,返回失败
|
||||
return std::make_pair(iterator(cur, this), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 查找下一个节点
|
||||
cur = cur->_next;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 头插挂到链表中(尾插也是可以的)
|
||||
Node* newnode = new Node(data);
|
||||
newnode->_next = _tables[index];
|
||||
_tables[index] = newnode;
|
||||
|
||||
++_num; // 更新已存储元素数量
|
||||
return std::make_pair(iterator(newnode, this), true);
|
||||
}
|
||||
|
||||
// 查找操作
|
||||
Node* Find(const K& key)
|
||||
{
|
||||
KeyOfT koft;
|
||||
|
||||
// 1. 计算键在表中映射的位置
|
||||
size_t index = HashFunc(key) % _tables.size();
|
||||
Node* cur = _tables[index];
|
||||
|
||||
// 2. 遍历链表查找匹配的键
|
||||
while (cur)
|
||||
{
|
||||
if (HashFunc(koft(cur->_data)) == HashFunc(key))
|
||||
{
|
||||
// 如果找到匹配的元素,返回其指针
|
||||
return cur;
|
||||
}
|
||||
// 继续查找下一个节点
|
||||
cur = cur->_next;
|
||||
}
|
||||
// 如果未找到,返回空指针
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Erase(const K& key)
|
||||
{
|
||||
KeyOfT koft;
|
||||
|
||||
// 1. 计算要删除元素的哈希值
|
||||
size_t index = HashFunc(key) % _tables.size();
|
||||
Node* prev = nullptr;
|
||||
Node* cur = _tables[index];
|
||||
|
||||
// 2. 遍历链表, 查找匹配的元素
|
||||
while (cur)
|
||||
{
|
||||
if (HashFunc(koft(cur->_data)) == HashFunc(key))
|
||||
{
|
||||
// 3. 找到元素后, 调整链表结构
|
||||
if (prev == nullptr)
|
||||
{
|
||||
// 如果要删除的元素是链表的第一个节点, 直接让桶指向下一个节点
|
||||
_tables[index] = cur->_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 否则,将前一个节点的 next 指向当前节点的下一个节点
|
||||
prev->_next = cur->_next;
|
||||
}
|
||||
// 4. 释放节点内存
|
||||
delete cur;
|
||||
--_num; // 元素数量减少
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 继续遍历链表
|
||||
prev = cur;
|
||||
cur = cur->_next;
|
||||
}
|
||||
}
|
||||
// 如果未找到该元素,返回 false
|
||||
return false;
|
||||
}
|
||||
|
||||
void Print() const
|
||||
{
|
||||
KeyOfT koft;
|
||||
int size = _tables.size();
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
std::cout << i << "\t";
|
||||
Node* cur = _tables[i];
|
||||
while (cur)
|
||||
{
|
||||
std::cout << koft(cur->_data) << "\t";
|
||||
cur = cur->_next;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Node*> _tables; // 哈希表存储桶
|
||||
size_t _num; // 记录着存储的数据个数
|
||||
};
|
||||
}
|
324
Windows_Unordered_Set_Map/Main.cpp
Normal file
324
Windows_Unordered_Set_Map/Main.cpp
Normal file
@ -0,0 +1,324 @@
|
||||
#include "Unordered_Set.hpp"
|
||||
#include "Unordered_Map.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <time.h>
|
||||
|
||||
void Test_unordered_set()
|
||||
{
|
||||
std::unordered_set<int> us; // Java里面取名叫HashSet
|
||||
us.insert(4);
|
||||
us.insert(2);
|
||||
us.insert(1);
|
||||
std::cout << "us 的 bucket 数量是: " << us.bucket_count()
|
||||
<< "\tus 的 负载因子 是: " << us.load_factor() << std::endl;
|
||||
us.insert(5);
|
||||
us.insert(6);
|
||||
us.insert(3);
|
||||
us.insert(5);
|
||||
us.insert(6);
|
||||
us.insert(3);
|
||||
us.insert(15);
|
||||
us.insert(16);
|
||||
us.insert(13);
|
||||
std::cout << "us 的 bucket 数量是: " << us.bucket_count()
|
||||
<< "\tus 的 负载因子 是: " << us.load_factor() << std::endl;
|
||||
us.insert(15);
|
||||
us.insert(16);
|
||||
us.insert(13);
|
||||
us.insert(9);
|
||||
us.insert(8);
|
||||
us.insert(10);
|
||||
us.insert(7);
|
||||
us.insert(12);
|
||||
std::cout << "us 的 bucket 数量是: " << us.bucket_count()
|
||||
<< "\tus 的 负载因子 是: " << us.load_factor() << std::endl;
|
||||
|
||||
// 会去重,但是不会自动排序
|
||||
std::unordered_set<int>::iterator it = us.begin();
|
||||
while (it != us.end())
|
||||
{
|
||||
std::cout << *it << " ";
|
||||
++it;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
std::set<int> s; // Java里面取名叫TreeSet
|
||||
s.insert(4);
|
||||
s.insert(2);
|
||||
s.insert(1);
|
||||
s.insert(5);
|
||||
s.insert(6);
|
||||
s.insert(3);
|
||||
s.insert(5);
|
||||
s.insert(6);
|
||||
s.insert(3);
|
||||
s.insert(15);
|
||||
s.insert(16);
|
||||
s.insert(13);
|
||||
s.insert(15);
|
||||
s.insert(16);
|
||||
s.insert(13);
|
||||
s.insert(9);
|
||||
s.insert(8);
|
||||
s.insert(10);
|
||||
s.insert(7);
|
||||
s.insert(12);
|
||||
// set会去重,会自动排序
|
||||
std::set<int>::iterator its = s.begin();
|
||||
while (its != s.end())
|
||||
{
|
||||
std::cout << *its << " ";
|
||||
++its;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
void Test_unordered_map()
|
||||
{
|
||||
std::unordered_map<std::string, std::string> dict;
|
||||
dict.insert(std::make_pair("hello", "你好"));
|
||||
dict.insert(std::make_pair("world", "世界"));
|
||||
dict.insert(std::make_pair("apple", "苹果"));
|
||||
dict.insert(std::make_pair("orange", "橘子"));
|
||||
dict.insert(std::make_pair("banana", "香蕉"));
|
||||
dict.insert(std::make_pair("peach", "桃子"));
|
||||
dict.insert(std::make_pair("peach", "桃子"));
|
||||
dict.insert(std::make_pair("peach", "桃子"));
|
||||
|
||||
dict.insert(std::make_pair("sort", "排序"));
|
||||
dict["string"] = "字符串";
|
||||
|
||||
std::unordered_map<std::string, std::string>::iterator it = dict.begin();
|
||||
while (it != dict.end())
|
||||
{
|
||||
std::cout << it->first << " " << it->second << std::endl;
|
||||
++it;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
std::map<std::string, std::string> mdict;
|
||||
mdict.insert(std::make_pair("hello", "你好"));
|
||||
mdict.insert(std::make_pair("world", "世界"));
|
||||
mdict.insert(std::make_pair("apple", "苹果"));
|
||||
mdict.insert(std::make_pair("orange", "橘子"));
|
||||
mdict.insert(std::make_pair("banana", "香蕉"));
|
||||
mdict.insert(std::make_pair("peach", "桃子"));
|
||||
mdict.insert(std::make_pair("peach", "桃子"));
|
||||
mdict.insert(std::make_pair("peach", "桃子"));
|
||||
|
||||
mdict.insert(std::make_pair("sort", "排序"));
|
||||
mdict["string"] = "字符串";
|
||||
|
||||
std::map<std::string, std::string>::iterator mit = mdict.begin();
|
||||
while (mit != mdict.end())
|
||||
{
|
||||
std::cout << mit->first << " " << mit->second << std::endl;
|
||||
++mit;
|
||||
}
|
||||
}
|
||||
|
||||
void Test_OP()
|
||||
{
|
||||
std::unordered_set<int> us;
|
||||
std::set<int> s;
|
||||
|
||||
const size_t n = 100000;
|
||||
std::vector<int> v;
|
||||
v.reserve(n); // reserve()函数是vector预留空间的,但是并不真正创建元素对象。
|
||||
// resize()函数是开空间+初始化
|
||||
srand(time(0));
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
v.push_back(rand());
|
||||
}
|
||||
|
||||
// 插入
|
||||
clock_t begin = clock();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
us.insert(v[i]);
|
||||
}
|
||||
clock_t end = clock();
|
||||
std::cout << "unordered_set insert time:\t" << end - begin << std::endl;
|
||||
|
||||
begin = clock();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
s.insert(v[i]);
|
||||
}
|
||||
end = clock();
|
||||
std::cout << "set insert time:\t\t" << end - begin << std::endl;
|
||||
|
||||
// 查找
|
||||
begin = clock();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
us.find(v[i]);
|
||||
}
|
||||
end = clock();
|
||||
std::cout << "unordered_set find time:\t" << end - begin << std::endl;
|
||||
|
||||
begin = clock();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
s.find(v[i]);
|
||||
}
|
||||
end = clock();
|
||||
std::cout << "set find time:\t\t\t" << end - begin << std::endl;
|
||||
|
||||
// 删除
|
||||
begin = clock();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
us.erase(v[i]);
|
||||
}
|
||||
end = clock();
|
||||
std::cout << "unordered_set erase time:\t" << end - begin << std::endl;
|
||||
|
||||
begin = clock();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
s.erase(v[i]);
|
||||
}
|
||||
end = clock();
|
||||
std::cout << "set erase time:\t\t\t" << end - begin << std::endl;
|
||||
}
|
||||
|
||||
void Test_Close_HashTable()
|
||||
{
|
||||
Lenyiin::Close_HashTable<int, int, Lenyiin::SetKeyOfT<int>> ht;
|
||||
ht.Insert(4);
|
||||
ht.Insert(14);
|
||||
ht.Insert(24);
|
||||
ht.Insert(5);
|
||||
ht.Insert(15);
|
||||
ht.Insert(25);
|
||||
ht.Insert(6);
|
||||
ht.Insert(16);
|
||||
|
||||
ht.Print();
|
||||
|
||||
ht.Erase(14);
|
||||
ht.Erase(24);
|
||||
ht.Print();
|
||||
|
||||
std::cout << "是否存在 5 ? " << (ht.Find(5) ? "true" : "false") << std::endl;
|
||||
}
|
||||
|
||||
void Test_Open_HashTable_1()
|
||||
{
|
||||
Lenyiin::Open_HashTable<int, int, Lenyiin::SetKeyOfT<int>, Lenyiin::_Hash<int>> ht;
|
||||
ht.Insert(4);
|
||||
ht.Insert(14);
|
||||
ht.Insert(24);
|
||||
ht.Insert(5);
|
||||
ht.Insert(15);
|
||||
ht.Insert(25);
|
||||
ht.Insert(6);
|
||||
ht.Insert(16);
|
||||
ht.Insert(26);
|
||||
ht.Insert(36);
|
||||
ht.Insert(33);
|
||||
ht.Insert(37);
|
||||
ht.Insert(32);
|
||||
|
||||
ht.Print();
|
||||
|
||||
ht.Erase(4);
|
||||
ht.Erase(14);
|
||||
|
||||
ht.Print();
|
||||
}
|
||||
|
||||
void Test_Open_HashTable_2()
|
||||
{
|
||||
Lenyiin::Open_HashTable<std::string, std::string, Lenyiin::SetKeyOfT<std::string>, Lenyiin::_Hash<std::string>> ht;
|
||||
ht.Insert("sort");
|
||||
ht.Insert("string");
|
||||
ht.Insert("left");
|
||||
ht.Insert("right");
|
||||
|
||||
std::cout << ht.HashFunc("abcd") << std::endl;
|
||||
std::cout << ht.HashFunc("aadd") << std::endl;
|
||||
}
|
||||
|
||||
void Test_Unordered_Set()
|
||||
{
|
||||
Lenyiin::Unordered_Set<int> s;
|
||||
s.Insert(1);
|
||||
s.Insert(5);
|
||||
s.Insert(4);
|
||||
s.Insert(2);
|
||||
s.Insert(5);
|
||||
s.Insert(5);
|
||||
s.Insert(53);
|
||||
s.Insert(54);
|
||||
|
||||
Lenyiin::Unordered_Set<int>::iterator it = s.begin();
|
||||
while (it != s.end())
|
||||
{
|
||||
std::cout << *it << " ";
|
||||
++it;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
s.Print();
|
||||
|
||||
std::cout << "查找 4: " << (s.Find(4) ? "true" : "false") << std::endl;
|
||||
std::cout << "查找 6: " << (s.Find(6) ? "true" : "false") << std::endl;
|
||||
|
||||
std::cout << "删除 2" << std::endl;
|
||||
s.Erase(2);
|
||||
s.Print();
|
||||
}
|
||||
|
||||
void Test_Unordered_Map()
|
||||
{
|
||||
Lenyiin::Unordered_Map<std::string, std::string> dict;
|
||||
dict.Insert(std::make_pair("sort", "排序"));
|
||||
dict.Insert(std::make_pair("left", "左边"));
|
||||
dict.Insert(std::make_pair("string", "字符串"));
|
||||
|
||||
dict["left"] = "剩余"; // 修改
|
||||
dict["end"] = "尾部"; // 插入 + 修改
|
||||
|
||||
// Unordered_Map<string, string>::iterator it = dict.begin();
|
||||
auto it = dict.begin();
|
||||
while (it != dict.end())
|
||||
{
|
||||
// cout << it->first << ":" << it->second << endl;
|
||||
std::cout << (*it).first << ":" << (*it).second << std::endl;
|
||||
++it;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
dict.Print();
|
||||
|
||||
std::cout << "查找 left: " << (dict.Find("left") ? "true" : "false") << std::endl;
|
||||
std::cout << "查找 up: " << (dict.Find("up") ? "true" : "false") << std::endl;
|
||||
|
||||
std::cout << "删除 left" << std::endl;
|
||||
dict.Erase("left");
|
||||
dict.Print();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
Test_unordered_set();
|
||||
Test_unordered_map();
|
||||
Test_OP();
|
||||
|
||||
Test_Close_HashTable();
|
||||
Test_Open_HashTable_1();
|
||||
Test_Open_HashTable_2();
|
||||
|
||||
Test_Unordered_Set();
|
||||
Test_Unordered_Map();
|
||||
|
||||
return 0;
|
||||
}
|
74
Windows_Unordered_Set_Map/Unordered_Map.hpp
Normal file
74
Windows_Unordered_Set_Map/Unordered_Map.hpp
Normal file
@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include "HashTable.hpp"
|
||||
|
||||
namespace Lenyiin
|
||||
{
|
||||
template <class K, class V, class Hash = _Hash<K>>
|
||||
class Unordered_Map
|
||||
{
|
||||
public:
|
||||
struct MapKOfT
|
||||
{
|
||||
const K& operator()(const std::pair<K, V>& kv)
|
||||
{
|
||||
return kv.first;
|
||||
}
|
||||
};
|
||||
|
||||
typedef typename Open_HashTable<K, std::pair<K, V>, MapKOfT, Hash>::iterator iterator;
|
||||
|
||||
iterator begin()
|
||||
{
|
||||
return _hashTable.begin();
|
||||
}
|
||||
|
||||
iterator end()
|
||||
{
|
||||
return _hashTable.end();
|
||||
}
|
||||
|
||||
// 构造函数: 指定哈希表的初始大小
|
||||
Unordered_Map(size_t bucket_count = 10)
|
||||
: _hashTable(bucket_count)
|
||||
{
|
||||
}
|
||||
|
||||
// 析构
|
||||
~Unordered_Map()
|
||||
{
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> Insert(const std::pair<K, V>& kv)
|
||||
{
|
||||
return _hashTable.Insert(kv);
|
||||
}
|
||||
|
||||
V& operator[](const K& key)
|
||||
{
|
||||
std::pair<iterator, bool> ret = _hashTable.Insert(std::make_pair(key, V()));
|
||||
return ret.first->second;
|
||||
}
|
||||
|
||||
// 查找元素
|
||||
bool Find(const K& key)
|
||||
{
|
||||
return _hashTable.Find(key);
|
||||
}
|
||||
|
||||
// 删除元素
|
||||
bool Erase(const K& key)
|
||||
{
|
||||
return _hashTable.Erase(key);
|
||||
}
|
||||
|
||||
// 打印
|
||||
void Print() const
|
||||
{
|
||||
_hashTable.Print();
|
||||
}
|
||||
|
||||
private:
|
||||
Open_HashTable<K, std::pair<K, V>, MapKOfT, Hash> _hashTable;
|
||||
};
|
||||
}
|
70
Windows_Unordered_Set_Map/Unordered_Set.hpp
Normal file
70
Windows_Unordered_Set_Map/Unordered_Set.hpp
Normal file
@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include "HashTable.hpp"
|
||||
|
||||
namespace Lenyiin
|
||||
{
|
||||
template <class K, class Hash = _Hash<K>>
|
||||
class Unordered_Set
|
||||
{
|
||||
public:
|
||||
struct SetKOfT
|
||||
{
|
||||
const K& operator()(const K& key)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
};
|
||||
|
||||
typedef typename Open_HashTable<K, K, SetKOfT, Hash>::iterator iterator;
|
||||
|
||||
iterator begin()
|
||||
{
|
||||
return _hashTable.begin();
|
||||
}
|
||||
|
||||
iterator end()
|
||||
{
|
||||
return _hashTable.end();
|
||||
}
|
||||
|
||||
// 构造函数: 指定哈希表的初始大小
|
||||
Unordered_Set(size_t bucket_count = 10)
|
||||
: _hashTable(bucket_count)
|
||||
{
|
||||
}
|
||||
|
||||
// 析构
|
||||
~Unordered_Set()
|
||||
{
|
||||
}
|
||||
|
||||
// 插入元素
|
||||
std::pair<iterator, bool> Insert(const K& key)
|
||||
{
|
||||
return _hashTable.Insert(key);
|
||||
}
|
||||
|
||||
// 查找元素
|
||||
bool Find(const K& key)
|
||||
{
|
||||
return _hashTable.Find(key);
|
||||
}
|
||||
|
||||
// 删除元素
|
||||
bool Erase(const K& key)
|
||||
{
|
||||
return _hashTable.Erase(key);
|
||||
}
|
||||
|
||||
// 打印
|
||||
void Print() const
|
||||
{
|
||||
_hashTable.Print();
|
||||
}
|
||||
|
||||
private:
|
||||
// 使用哈希表作为底层数据结构
|
||||
Open_HashTable<K, K, SetKOfT, Hash> _hashTable;
|
||||
};
|
||||
}
|
BIN
Windows_Unordered_Set_Map/Windows_.6c808d8b/x64/Debug/Main.obj
Normal file
BIN
Windows_Unordered_Set_Map/Windows_.6c808d8b/x64/Debug/Main.obj
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1 @@
|
||||
E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\Main.cpp;E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\Windows_.6c808d8b\x64\Debug\Main.obj
|
@ -0,0 +1,2 @@
|
||||
PlatformToolSet=v143:VCToolArchitecture=Native64Bit:VCToolsVersion=14.41.34120:TargetPlatformVersion=10.0.22000.0:
|
||||
Debug|x64|E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\|
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
^E:\GIT 仓库\公开仓库\10_UNORDERED-SET-MAP\WINDOWS_UNORDERED_SET_MAP\WINDOWS_.6C808D8B\X64\DEBUG\MAIN.OBJ
|
||||
E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\Windows_.6c808d8b\x64\Debug\Windows_Unordered_Set_Map.ilk
|
Binary file not shown.
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project>
|
||||
<ProjectOutputs>
|
||||
<ProjectOutput>
|
||||
<FullPath>E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\x64\Debug\Windows_Unordered_Set_Map.exe</FullPath>
|
||||
</ProjectOutput>
|
||||
</ProjectOutputs>
|
||||
<ContentFiles />
|
||||
<SatelliteDlls />
|
||||
<NonRecipeFileRefs />
|
||||
</Project>
|
Binary file not shown.
@ -0,0 +1,38 @@
|
||||
Main.cpp
|
||||
E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\Main.cpp(134,15): warning C4244: “参数”: 从“time_t”转换到“unsigned int”,可能丢失数据
|
||||
E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\Main.cpp(161,12): warning C4834: 放弃具有 [[nodiscard]] 属性的函数的返回值
|
||||
E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\Main.cpp(169,11): warning C4834: 放弃具有 [[nodiscard]] 属性的函数的返回值
|
||||
E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\HashTable.hpp(666,22): warning C4267: “初始化”: 从“size_t”转换到“int”,可能丢失数据
|
||||
(编译源文件“Main.cpp”)
|
||||
E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\HashTable.hpp(666,22):
|
||||
模板实例化上下文(最早的实例化上下文)为
|
||||
E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\Main.cpp(215,85):
|
||||
查看对正在编译的 类 模板 实例化“Lenyiin::Open_HashTable<int,int,Lenyiin::SetKeyOfT<int>,Lenyiin::_Hash<int>>”的引用
|
||||
E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\HashTable.hpp(663,14):
|
||||
在编译 类 模板 成员函数“void Lenyiin::Open_HashTable<int,int,Lenyiin::SetKeyOfT<int>,Lenyiin::_Hash<int>>::Print(void) const”时
|
||||
E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\Main.cpp(230,13):
|
||||
请参阅 "Test_Open_HashTable_1" 中对 "Lenyiin::Open_HashTable<int,int,Lenyiin::SetKeyOfT<int>,Lenyiin::_Hash<int>>::Print" 的第一个引用
|
||||
|
||||
E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\HashTable.hpp(281,22): warning C4267: “初始化”: 从“size_t”转换到“int”,可能丢失数据
|
||||
(编译源文件“Main.cpp”)
|
||||
E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\HashTable.hpp(281,22):
|
||||
模板实例化上下文(最早的实例化上下文)为
|
||||
E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\Main.cpp(194,65):
|
||||
查看对正在编译的 类 模板 实例化“Lenyiin::Close_HashTable<int,int,Lenyiin::SetKeyOfT<int>>”的引用
|
||||
E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\HashTable.hpp(279,14):
|
||||
在编译 类 模板 成员函数“void Lenyiin::Close_HashTable<int,int,Lenyiin::SetKeyOfT<int>>::Print(void)”时
|
||||
E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\Main.cpp(204,13):
|
||||
请参阅 "Test_Close_HashTable" 中对 "Lenyiin::Close_HashTable<int,int,Lenyiin::SetKeyOfT<int>>::Print" 的第一个引用
|
||||
|
||||
E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\HashTable.hpp(58,20): warning C4101: “koft”: 未引用的局部变量
|
||||
(编译源文件“Main.cpp”)
|
||||
E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\HashTable.hpp(58,20):
|
||||
模板实例化上下文(最早的实例化上下文)为
|
||||
E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\HashTable.hpp(56,14):
|
||||
在编译 类 模板 成员函数“void Lenyiin::Close_HashTable<int,int,Lenyiin::SetKeyOfT<int>>::CheckCapacity(void)”时
|
||||
E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\HashTable.hpp(143,26):
|
||||
请参阅 "Lenyiin::Close_HashTable<int,int,Lenyiin::SetKeyOfT<int>>::Insert" 中对 "Lenyiin::Close_HashTable<int,int,Lenyiin::SetKeyOfT<int>>::CheckCapacity" 的第一个引用
|
||||
E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\Main.cpp(195,14):
|
||||
请参阅 "Test_Close_HashTable" 中对 "Lenyiin::Close_HashTable<int,int,Lenyiin::SetKeyOfT<int>>::Insert" 的第一个引用
|
||||
|
||||
Windows_Unordered_Set_Map.vcxproj -> E:\Git 仓库\公开仓库\10_unordered-set-map\Windows_Unordered_Set_Map\x64\Debug\Windows_Unordered_Set_Map.exe
|
BIN
Windows_Unordered_Set_Map/Windows_.6c808d8b/x64/Debug/vc143.idb
Normal file
BIN
Windows_Unordered_Set_Map/Windows_.6c808d8b/x64/Debug/vc143.idb
Normal file
Binary file not shown.
BIN
Windows_Unordered_Set_Map/Windows_.6c808d8b/x64/Debug/vc143.pdb
Normal file
BIN
Windows_Unordered_Set_Map/Windows_.6c808d8b/x64/Debug/vc143.pdb
Normal file
Binary file not shown.
31
Windows_Unordered_Set_Map/Windows_Unordered_Set_Map.sln
Normal file
31
Windows_Unordered_Set_Map/Windows_Unordered_Set_Map.sln
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.11.35312.102
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Windows_Unordered_Set_Map", "Windows_Unordered_Set_Map.vcxproj", "{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}.Debug|x64.Build.0 = Debug|x64
|
||||
{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}.Debug|x86.Build.0 = Debug|Win32
|
||||
{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}.Release|x64.ActiveCfg = Release|x64
|
||||
{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}.Release|x64.Build.0 = Release|x64
|
||||
{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}.Release|x86.ActiveCfg = Release|Win32
|
||||
{6C808D8B-0CB3-42B6-AF2E-ED6384CC59B8}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {CDBD2AFD-9BDF-4941-A594-4E0BFAA55F03}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
140
Windows_Unordered_Set_Map/Windows_Unordered_Set_Map.vcxproj
Normal file
140
Windows_Unordered_Set_Map/Windows_Unordered_Set_Map.vcxproj
Normal file
@ -0,0 +1,140 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{6c808d8b-0cb3-42b6-af2e-ed6384cc59b8}</ProjectGuid>
|
||||
<RootNamespace>WindowsUnorderedSetMap</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="HashTable.hpp" />
|
||||
<ClInclude Include="Unordered_Map.hpp" />
|
||||
<ClInclude Include="Unordered_Set.hpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Main.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="HashTable.hpp">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Unordered_Set.hpp">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Unordered_Map.hpp">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Main.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user