在STL中,unordered_map与unordered_set的查找是天花板级别的,他们的底层逻辑很简单,就是哈希捅,哈希捅的逻辑十分简单,就是不一样的链表和数组而已(个人认为)。但是千万不要绝的实现unordered_map与unordered_set很简单,就像做饭一样,我们每个人都可以做出挂面,但是最后吃进嘴的感觉,味道是不一样,大厨做出来的大概率会比一个做饭小白做的好吃,而unordered_map与unordered_set就像做饭一样,想实现哈希捅不难,但是封装接口是真的难。下面是代码:
//unordered_map头文件
#pragma once
#include"Hash.h"
namespace myunmap
{
template
class myunm
{
public:
struct map;
typedef Hash::HashNode> node;
typedef typename Hash::Iterator, map,pair&, pair*, Hash::HashFunc> iterator;
struct map
{
const K& operator()(const pair& x)
{
return x.first;
}
};
pair insert(const pair& x)
{
return _Table.insert(x);
}
node* find(const K& x)
{
return _Table.find(x);
}
iterator begin()
{
return _Table.begin();
}
iterator end()
{
return _Table.end();
}
V& operator[](const K& data)
{
pair ret = _Table.insert(make_pair(data, V()));
return ret.first->second;
}
private:
Hash::HashTable,map,Hash::HashFunc> _Table;
};
}
//unordered_set头文件
#pragma once
#include "Hash.h"
namespace myunset
{
template
class myset
{
public:
struct set;
typedef Hash::HashNode node;
typedef typename Hash::Iterator> iterator;
struct set
{
const K& operator()(const K& x)
{
return x;
}
};
pair insert(const K& x)
{
return _Table.insert(x);
}
node* find(const K& x)
{
return _Table.find(x);
}
iterator begin()
{
return _Table.begin();
}
iterator end()
{
return _Table.end();
}
private:
Hash::HashTable> _Table;
};
}
//Hash.h头文件
#pragma once
#include
#include
#include
#include
//测试代码
#include"Hash.h"
#include"unordered_map.h"
#include"unordered_set.h"
int main()
{
/*Hash::HashTable s;
s.insert(1);
s.insert(1);
s.insert(1);
s.insert(1);*/
myunmap::myunm s;
vector v = { 1,1,1,1,1,1,1,1 };
//myunmap::myunm::iterator sit = s.begin();
for (auto e : v)
{
s[e]++;
}
for (auto& e : s)
cout << e.first << endl;
/*myunset::myset h;
h.insert(1);
h.insert(2);
h.insert(3);
h.insert(4);
h.insert(5);
h.insert(6);
h.insert(7);
myunset::myset::iterator sit = h.begin();
while (sit != h.end())
{
cout << (*sit) << endl;
++sit;
}*/
return 0;
}
怎么说,实现哈希捅的时候,前前后后大概用了一个小时左右,封装接口用了三个小时左右,封装代码的过程怎么说,难受,其实在封装其他的时候,感觉还可以,但是到迭代器的那一块,真的是感觉绕糊了,为什么说很绕呢?其实也怪我写的位置,在最开始,所以把下面所有的类都声明了一遍。所以导致看起来很乱。行了,说说怎么实现的吧。
其他地方就不说了,主要是迭代器那一块。
迭代器的模版传参数,我刚开始写的是K,K&,K*。但是这样写你会发现一个问题,那就是没有哈希捅的指针,而要实现迭代器,哈希捅的指针是必不可少的,所以,这就很矛盾。所以不可以这样设置参数。因为要用哈希捅的指针,所以哈希捅的四个模版参数不能少,其实如果没有啥的话,就可以实现了。但是我又加了两个参数,那就是ref,ptr。这样就可以方便一些。好了,哈希捅的指针问题解决之后,就相当于是迭代器中的复杂问题都解决了。但是下一个问题又来了,那就是operator[]怎么办?这个重载函数的参数应该是K,但是你要插入的话,像unordered_map的插入是pair啊,所以,此时就必须要在unordered_map的这个文件中,调用Hash文件中的插入,在传下去。
以上就是两个难点,虽然说起来简单,但是自己实现的话,我觉还是有点难度的,实现封装比实现哈希捅难多了,尤其是往下传这个过程,特别绕。我个人认为,map,set的封装都比unordered_map,unordered_set简单,主要是unordered_map,unordered_set这两个是要用哈希函数来映射的,所以必须要支持取余,但是如果是string呢?string的话就不用自己实现的了?所以此时需要一个仿函数。而map,set不需要,红黑树是我只要知道你是pair还是K就好了。所以只要一个仿函数就可以了。
最后,希望大家支持一下吧!!