数据结构哈希表--线性探测和哈希桶及unordered_set,unordered_map代码示范
Posted zhaocx111222333
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构哈希表--线性探测和哈希桶及unordered_set,unordered_map代码示范相关的知识,希望对你有一定的参考价值。
哈希桶
#include<iostream>
#include<vector>
using namespace std;
//开散列
//hash表封装了一个链表指针数组,和一个size(存放的元素个数)
//链表指针数组里面就是单链表的节点
//单链表节点
template<class V>
struct HashNode{
V _val;
HashNode<V>* _next;
//再写一个构造函数,插入等操作需要在某位置新建节点
HashNode(const V& val)
:_val(val)//可能是K,也可能是pair<K,v>
, _next(nullptr)
{}
};
//在实现了hashtable后,需要实现迭代器
//哈希表的迭代器需要封装链表节点
//由于hashtable的具体结构不确定,我们还需要一个hashtable来辅助迭代器的实现
//这时就有一个问题,iterator需要hashtable,hashtable需要iterator,这时就需要前置声明和友元来解决
template<class K, class V, class KeyOfValue, class HashFun=HashFun<K>>
class HashTable;
//迭代器的实现:
template<class K, class V, class KeyOfValue, class HashFun = HashFun<K>>
struct Hashiterator{
//成员:哈希表指针,节点指针
typedef Hashiterator<K, V, KeyOfValue, HashFun> Self;
typedef HashTable<K, V, KeyOfValue, HashFun> HT;
typedef HashNode<V> Node;
Node* _node;
HT* _hptr;
//迭代器的构造函数
Hashiterator(Node* node, HT* hptr)
:_node(node)
, _hptr(hptr)
{}
V& operator*(){
return _node->_val;
}
V* operator->(){
return &_node->_val;//返回??
}
bool operator!=(const Self& it){
return _node != it._node;
}
//迭代器的++需要考虑2种情况
//1.链表有next
//2.没有next
Self& operator++(){
if (_node->_next){
_node = _node->_next;
}
else{
//查找下一个非空链表的头结点
//先找出该节点的hash位置,再向后查找
KeyOfValue kov;
HashFun hfun;
//这里想要使用哈希表指针指向的指针数组的私有成员_ht,需要在hashtable里友元迭代器类
size_t idx = hfun(kov(_node->_val)) % _hptr->_ht.size();
++idx;
for (; idx < _hptr->_ht.size(); ++idx){//需要遍历后续链表头节点
if (_hptr->_ht[idx]){//如果哈希表的vector对应的索引存在就找到
_node = _hptr->_ht[idx];
break;
}
}
//没有找到的情况
if (idx == _hptr->_ht.size()){//和vector的长度比,不可和实际元素个数比
_node = nullptr;
}
}
return *this;
}
};
//接下来是哈希表的实现
//kov是用来获取节点val的K值的
template<class K,class V,class KeyOfValue,class HashFun>
class HashTable{
public:
typedef HashNode<V> Node;
typedef Hashiterator<K, V, KeyOfValue, HashFun> iterator;
//友元
template<class K, class V, class KeyOfValue, class HashFun>
friend struct Hashiterator;
//构造函数(可以写个缺省值创建vector)
HashTable(int n = 10)
:_ht(n)
, _size(0)
{}
//写出迭代器
iterator begin(){
for (size_t i = 0; i < _ht.size(); ++i){
if (_ht[i]){
return iterator(_ht[i], this);//谁调用迭代器就用那个哈希表创建迭代器
}
}
return iterator(nullptr, this);
}
iterator end(){
return iterator(nullptr, this);
}
pair<iterator, bool> insert(const V& val){
//bool insert(const V& val){
//0.检查容量
checkCapacity();
//1.计算哈希位置
//需要用k值查找,所以用kov
KeyOfValue kov;
HashFun hfun;
int idx = hfun(kov(val)) % _ht.size();
//2.检查是否存在
Node* cur = _ht[idx];
while (cur){
if (kov(cur->_val) == kov(val)){//如果节点的val(的K)相等
return make_pair(iterator(cur, this), false);
//return false;
}
cur = cur->_next;
}
//3.插入指针数组(头插)
cur = new Node(val);
cur->_next = _ht[idx];
_ht[idx] = cur;
++_size;
return make_pair(iterator(cur, this), true);
//return true;
}
size_t GetNextPrime(size_t prime)
{
const int PRIMECOUNT = 28;
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
};
size_t i = 0;
for (; i < PRIMECOUNT; ++i)
{
if (primeList[i] > primeList[i])
return primeList[i];
}
return primeList[i];
}
void checkCapacity(){
if (_size == _ht.size()){//如果实际的数据和指针数组的长度相同需要扩容
//计算容量大小
int newc = _size == 0 ? 10 : 2 * _size;
//开辟空间
vector<Node*> newht(newc);
KeyOfValue kov;
HashFun hfun;
//遍历旧表插入新表
for (size_t i = 0; i < _ht.size(); ++i){
//for用来遍历指针数组的链表头节点
Node* cur = _ht[i];
//while遍历链表
while (cur){
//需要记录下一个位置,因为我们是修改指针的指向,下一个不存会丢失
Node* next = cur->_next;
//计算新的表的hash位置
int idx = hfun(kov(cur->_val)) % newht.size();
//头插
cur->_next = newht[idx];
newht[idx] = cur;
cur=next;
}
//需要将旧表置空
_ht[i] = nullptr;
}
//交换表,旧表就跟着vector的析构函数销毁了
swap(_ht, newht);
}
}
Node* Find(const K& key){
KeyOfValue kov;
HashFun hfun;
int idx = key % _ht.size();
//2.检查是否存在
Node* cur = _ht[idx];
while (cur){
if hfun((kov(cur->_val)) == key){//如果节点的val(的K)相等
return cur;
}
cur = cur->_next;
}
return nullptr;
}
bool Erase(const K& key){
KeyOfValue kov;
HashFun hfun;
int idx = key % _ht.size();
Node* cur = _ht[idx];
if (!cur){
return false;
}
else if (cur->_next == nullptr){
delete cur;
_ht[idx] = nullptr;
return true;
}
else{
Node* prev = cur;
cur = cur->_next;
while (cur){
if (hfun(kov(cur->_val)) == key){
Node* tmp = cur;
cur = cur->_next;
prev->_next = tmp->_next;
return true;
}
}
}
return false;
}
//X开散列删除
/*Node* prev = nullptr;
Node* pret = nullptr;
while (cur){
if (kov(cur->_val) == key ){//如果节点的val(的K)相等
//Node* next = cur->_next;
//prev = cur;
if (cur == _ht[idx])
_ht[idx] = cur->_next;
else
prev->_next = cur->_next;
delete cur;
--_size;
}
cur = cur->_next;
}
return nullptr;*/
private:
vector<Node*> _ht;
int _size;
};
//哈希函数
template <class K>
struct Hashfun{
size_t operator()(const K& key){
return key;
}
};
//将字符串转数字的哈希函数
struct Hashfunstring
{
size_t operator()(const string& key){
size_t hash = 0;
for (const auto& ch : key){
hash = hash * 131 + ch;
}
return hash;
}
};
//也可以这样写
template<>
struct Hashfun<string>
{
size_t operator()(const string& key){
size_t hash = 0;
for (const auto& ch : key){
hash = hash * 131 + ch;
}
return hash;
}
};
//自定义类型的哈希函数示例:
class A{
public:
int _a;
string _b;
double _d;
//自定义类型需要手写==运算符重载
bool operator==(const A& a){
return _a == a._a && _b == a._b && _d == a._d;
}
};
struct HashfunA{
size_t operator()(const A& a){
return a._a ;
}
};
template <class K>
struct HashFun
{
size_t operator()(const K& key){
return key;
}
};
map和set
//因为我的hashfun给了缺省,so这里可以不写
//哈希表底层的map实现
//map底层的哈希表的指针数组放的是,成员为pair的单链表指针
template <class K,class V>
class Map{
//因为哈希表是三个泛型,第三个为获取K的仿函数
struct MapKeyOfValue
{
//仅需要重载()运算符即可获取K值
const K& operator()(const pair<K, V>& val){
return val.first;
}
};
public:
typedef typename HashTable<K, pair<K, V>, MapKeyOfValue>::iterator iterator;
pair<iterator, bool> insert(const pair<K, V>& val){
return _ht.insert(val);
}
iterator begin(){
return _ht.begin();
}
iterator end(){
return _ht.end();
}
V& operator[](const K& key){
pair<iterator, bool> ret = _ht.insert(make_pair(key, V()));
return ret.first->second;
}
bool earse(const K& key){
return _ht.Erase(key);
}
private:
HashTable<K, pair<K, V>, MapKeyOfValue> _ht;
};
template <class K>
class Set{
//因为哈希表是三个泛型,第三个为获取K的仿函数
struct SetKeyOfValue
{
//仅需要重载()运算符即可获取K值
const K& operator()(const K& val){
return val;
}
};
public:
typedef typename HashTable<K, K, SetKeyOfValue>::iterator iterator;
pair<iterator, bool> insert(const K& val){
return _ht.insert(val);
}
iterator begin(){
return _ht.begin();
}
iterator end(){
return _ht.end();
}
bool earse(const K& val){
return _ht.Erase(val);
}
private:
HashTable<K, K, SetKeyOfValue> _ht;
};
void test(){
/*Set<int> s;
s.insert(1);
s.insert(11);
s.insert(12);
s.insert(13);
s.insert(44);
s.insert(5);
s.insert(7);
s.insert(8);
s.insert(2);
s.insert(3);
s.earse(1);
s.earse(11);
s.earse(12);
s.earse(100);*/
Map<int, int> s;
s.insert(make_pair(1, 1));
s[1] = 5;
s[5] = 10;
s[15] = 15;
s[4] = 4;
s.earse(1);
//cout << s.find(2) << endl;
for (auto& e : s){
cout << e.first << " " << e.second << endl;
}
}
int main(){
test();
system("pause");
return 0;
}
线性探测
#include<vector>
#include<iostream>
using namespace std;
//闭散列主要是线性探测
//每一个节点是一种标志位和一个值
//哈希表里面是一个节点的vector和有效元素个数
enum STATE
{
EXIST,
DELETE,
EMPTY
};
//我们让节点里存放kv键值对
template<class K, class V>
struct HashNode
{
pair<K, V> _kv;
STATE _state = EMPTY;
};
//哈希表的实现:
template<class K, class V>
class HashTable
{
public:
typedef HashNode<K,以上是关于数据结构哈希表--线性探测和哈希桶及unordered_set,unordered_map代码示范的主要内容,如果未能解决你的问题,请参考以下文章