#pragma once

#include<vector>
#include<string>
#include<iostream>
using std::cout;
using std::endl;
using std::pair;
using std::make_pair; namespace HashBucket
{ template<class T>
struct HashNode
{
HashNode* _next = nullptr;
T _data; HashNode(const T& data)
:_data(data)
{} }; //HashNode_end //见27.
template<class K>
struct HashFunc
{
size_t operator()(const K& key)
{
return key;
}
};
template<>
struct HashFunc<std::string>
{
size_t operator()(const std::string& s)
{
size_t ret = 0;
for (auto ch : s)
{
ret += ch;
ret *= 31;
}
return ret;
}
}; //根据声明顺序,使用下面的类需要前置声明
template<class K, class T, class keyOfT, class Hash >
class HashTable; template<class K , class T, class Ref, class Ptr, class keyOfT,class Hash>
struct __Hash_iterator
{
//迭代器怎么写?
/**
* 1.迭代器需要什么模板类?
* -> 先写符号重载,看需要什么:写了++,需要结点,哈希表
*
* 2.需要什么函数重载?
* -> ++ . -- , != , * , -> ,
*
* 3.写外部函数调用,看需要什么
*/ typedef __Hash_iterator<K, T, T&, T*, keyOfT, Hash > iterator;
typedef __Hash_iterator<K, T, Ref, Ptr, keyOfT, Hash > Self; typedef HashNode<T> node;
typedef HashTable<K, T, keyOfT,Hash> HashTable; node* _node;
const HashTable* _ht; //不允许修改 __Hash_iterator(node* node, const HashTable* ht) //普通构造函数 --- 绝对不能用引用,因为迭代器是有可能会修改指针,使用引用可能会改崩原指针,
:_node(node)
,_ht(ht)
{} __Hash_iterator(const iterator& it)
:_node(it._node)
,_ht(it._ht)
{} Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
bool operator!=(const Self& s)
{
return _node != s._node;
} Self& operator++() //迭代器++返回什么? 返回新的迭代器
{
/** 迭代器怎么++ ?
* 条件:
*
* 1.当前结点为空
* a.循环,计算哈希值,找下一个不为空的数组
* 循环出口:1.哈希值超过数组最大长度 2.找到不为空的元素
* 循环入口:1
* 循环结束后:返回空--没找到
*
* 2.当前结点非空
* a.返回下一个位置
*
*/
Hash hash;
keyOfT kot;
if (_node->_next) //_node&& _node->_next 迭代器不会为空,直到end为止,end再加就崩了,看库怎么限制法
{
_node = _node->_next; }
else
{
size_t hashi = hash(kot(_node->_data))% _ht->_tables.size();//计算哈希值
++hashi;//这个已经是空了,从下一个开始,
size_t sz = _ht->_tables.size();
while (hashi < sz)
{
if (_ht->_tables[hashi])
{
_node = _ht->_tables[hashi];
break;
}
++hashi;
}
if (sz == hashi)
{
_node = nullptr;
}
}
return *this;
} //operater++_end; }; //iterator_end; template<class K, class T,class keyOfT,class Hash >
class HashTable
{
template<class K, class T, class Ref, class Ptr, class keyOfT, class Hash>
friend struct __Hash_iterator; public:
typedef HashNode<T> node;
typedef __Hash_iterator<K, T, T&, T*, keyOfT, Hash> iterator;
typedef __Hash_iterator<K, T, const T&,const T*, keyOfT, Hash> const_iterator;
private:
size_t _n = 0;
std::vector<node*> _tables; public:
iterator begin()
{
node* cur = nullptr;
for (size_t i = 0; i < _tables.size(); ++i)
{
if (_tables[i])
{
cur = _tables[i];
break;
}
}
return iterator(cur,this);
} // begin_end; iterator end()
{
return iterator(nullptr, this);
} const_iterator begin() const
{
return begin(); //类型转换即可
} const_iterator end() const
{
return end(); //类型转换即可
} ~HashTable()
{
for (auto& cur : _tables)
{
while (cur)
{
node* next = cur->_next;
delete cur;
cur = next;
}
}
//析构,只需要析构主动申请的空间,栈空间不需要,防止内存泄漏
} size_t GetNextPrime(size_t prime)
{
static const int __stl_num_primes = 28;
static const unsigned long __stl_prime_list[__stl_num_primes] =
{
53, 97, 193, 389, 769,
1543, 3079, 6151, 12289, 24593,
49157, 98317, 196613, 393241, 786433,
1572869, 3145739, 6291469, 12582917, 25165843,
50331653, 100663319, 201326611, 402653189, 805306457,
1610612741, 3221225473, 4294967291
};
size_t i = 0;
for ( ;i < __stl_num_primes; ++i)
{
if (__stl_prime_list[i] > prime)
return __stl_prime_list[i];
} return __stl_prime_list[i];
} pair<iterator,bool> insert(const T& data)
{
keyOfT kot;
Hash hash;
iterator it = find(kot(data));
if (it!=end())
{
return make_pair(it,false);
} if (_n == _tables.size())
{
size_t newsize = GetNextPrime(_tables.size()); std::vector<node*> newht(newsize, nullptr); for (auto& cur : _tables)
{
while (cur)
{
node* next = cur->_next; size_t hashi = hash(kot(cur->_data)) % newht.size(); cur->_next = newht[hashi];
newht[hashi] = cur; cur = next;
}
}
_tables.swap(newht);
}
size_t hashi = hash(kot(data)) % _tables.size(); node* newnode = new node(data);
newnode->_next = _tables[hashi];
_tables[hashi] = newnode;
++_n; return make_pair(iterator(_tables[hashi],this),true);
}//insert_end iterator find(const K& key)
{
keyOfT kot;
Hash hash; if (_n == 0)
{
return end();
}
size_t hashi = hash(key) % _tables.size();
node* cur = _tables[hashi]; while (cur)
{
if (kot(cur->_data) == key)
{
break;
}
cur = cur->_next;
} return iterator(cur,this);
} //find_end bool erase(const K& key) //可以返回bool,库中返回 1或0 和 迭代器,选择bool也可以
{
keyOfT kot; Hash hash;
size_t hashi = hash(key) % _tables.size(); node* cur = _tables[hashi];
node* prev = nullptr;
while (cur)
{
if (kot(cur->_data) == key)
{
if (!prev)
{
_tables[hashi] = cur->_next;
}
else
{
prev->_next = cur->_next;
}
delete cur; return true;
}
prev = cur;
cur = cur->_next;
} return false;
}//erase_end size_t MaxBucketSize()
{
size_t max = 0;
for (size_t i = 0; i < _tables.size(); ++i)
{
auto cur = _tables[i];
size_t size = 0;
while (cur)
{
++size;
cur = cur->_next;
} if (size > max)
{
max = size;
}
} return max;
} };//HashBucket_end }

STL-unordered_hashtable模拟实现的更多相关文章

  1. <泛> STL - vector 模拟实现

    今天为大家带来一个模拟STL-vector的模板实现代码. 首先看一下测试结果,之后再为大家呈现设计 测试效果 测试代码 #include<iostream> #include<ve ...

  2. 洛谷 P1739 表达式括号匹配【STL/stack/模拟】

    题目描述 假设一个表达式有英文字母(小写).运算符(+,-,*,/)和左右小(圆)括号构成,以"@"作为表达式的结束符.请编写一个程序检查表达式中的左右圆括号是否匹配,若匹配,则返 ...

  3. <泛> STL - stack 模拟实现

    今天,看C++Template的时候看到那人写了一个Stack,于是乎,手痒,自己也写了一个,在拜读了STD文件和C++模板元编程某些小节之后,你们就看到了这篇代码. 经过上述一番经历之后,我重新写了 ...

  4. STL string 模拟

    下面的代码来自c++ primer plus第5版第12章,书中代码写的非常好: // string1.h -- fixed and augmented string class definition ...

  5. UVa 12219 Common Subexpression Elimination (stl,模拟,实现)

    一般来说,把一颗子树离散成一个int,把一个结点的字符离散成一个int会方便处理 直接map离散.当然一个结点最多只有4个小写字母,也可以直接编码成一个27进制的整数,舍掉0,为了区分0和0000. ...

  6. 【STL+模拟】UVa 506 - System Dependencies

    System Dependencies  Components of computer systems often have dependencies--other components that m ...

  7. hiho一下 第四十七周 拓扑排序一 【静态数组链式前向星存储结构实现 + 拓扑跳出 】

    题目1 : 拓扑排序·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 由于今天上课的老师讲的特别无聊,小Hi和小Ho偷偷地聊了起来. 小Ho:小Hi,你这学期有选什么 ...

  8. 【数据结构】洛谷2019 OI春令营 - 普及组 作业

    [P3662][USACO17FEB]Why Did the Cow Cross the Road II S 求解连续的k个数的最大值,利用前缀和维护即可. #include<bits/stdc ...

  9. 基于各种基础数据结构的SPFA和各种优化

    一.基于各种数据结构的SPFA 以下各个数据均为不卡SPFA的最短路模板:P3371 [模板]单源最短路径(弱化版)的测试时间 1.STL队列:用时: 1106ms / 内存: 8496KB #inc ...

  10. LeetCode双周赛#36

    1604. 警告一小时内使用相同员工卡大于等于三次的人 题目链接 题意 给定两个字符串数组keyName和keyTime,分别表示名字为keytime[i]的人,在某一天内使用员工卡的时间(格式为24 ...

随机推荐

  1. element-ui中Select 选择器value-key的使用

    场景描述 很多时候我们都需要使用下拉框 Select 选择器. 在获取值的时候,通常只需要传递对应的id给后端就行了. 但是特殊情况,后端不想去查库,不仅需要我们id,还有name,code之类的. ...

  2. 正则表达式match方法和search方法

    正则表达式, //match() 方法可在字符串内检索指定的值 找到返回相关数据,找不到返回null var part = /Box/ig; var str = "this is box,i ...

  3. 【小测试】玩一玩 VictoriaMetrics 的 force merge

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 我是期望通过备份来建立 VictoriaMetrics 的 ...

  4. Gorm实战,轻松掌握数据库增删改查技巧!

    Gorm实战,轻松掌握数据库增删改查技巧! CRUD通常指数据库的增删改查操作,本文详细介绍了如何使用GORM实现创建.查询.更新和删除操作. 目录 Gorm实战,轻松掌握数据库增删改查技巧! 一.C ...

  5. 宏观上看Spring创建对象的过程

    宏观上看Spring创建对象的过程 对于对象而言,可以分为简单对象和复杂对象: 简单对象 简单对象指可以直接new的对象: Spring在创建这些对象时,是基于反射来完成的. 复杂对象 复杂对象指不能 ...

  6. 关于debug一晚上的一些思考,做开发到底要养成什么习惯?

    总结:日志一定要写,日志一定要写,日志一定要写! 今天晚上是我学开发过程中很不一样的一晚,今晚学到了很多. 虽然我也只是一个开发的初学小白,今天的debug分享是我的一个小方法和一个小记录,如果大佬们 ...

  7. 设计模式 - 创建型模式 - 单例模式(C++)

    1.前言 单例模式属于创建型模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点. 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方 ...

  8. 问题:Duplicate报错RMAN-03009, ORA-17628, ORA-19505

    前面文章提到,这周末帮一个客户测试报错场景: 客户通过duplicate生产备库的方式创建cascade备库. 发现每次都会遇到两个文件报错,ORA-17628: Oracle error 19505 ...

  9. 小知识:RMAN备份当前控制文件报错ORA-245

    在一个备份的case上遇到备份控制文件报错ORA-245,最终通过修改snapshot controlfile默认位置到ASM磁盘组后解决. 1.问题复现 回来后就想快速记录下这个小知识点,打开尘封的 ...

  10. .Net Core + 微信赋能企业级智能客服系统--学习笔记

    摘要 围绕目前需求猛增的微信及移动端企业智能客服业务,利用 .NET Core 的一系列优秀特性及 SignalR 模块打造全双工.跨微信/QQ/钉钉等应用平台.跨系统平台.跨终端.支持企业级并发的移 ...