C++ HashMap
来源:互联网 发布:2017 大数据 大会 编辑:程序博客网 时间:2024/06/05 08:05
C++ HashMap
参考自boost库。
- 基本原理:
- 使用连续的内存块(数组)来存储数据,通过一个hash函数(即使每一个元素值都能形成固定的数组下标值),然后数组在相应的位置存起来,不能保证每个元素的关键值与hash函数值是一一对应的(可以有多个元素生成一样的hash值),这时候就需要解决冲突。
我们把数组叫做桶(因为数组把很多相似的元素存放在同一个位置)。 - 流程:
- 查找元素
- 元素的关键值通过hash函数计算得到hash值
- 得到桶号(数组下标位置)
- 比较桶的元素值(因为只有一次hash函数的值并不准确)
- 取出相同的元素的关键值,不相等则结束 插入元素
- 元素的关键值通过hash函数计算得到hash值
- 得到桶号(数组下标位置)
- 存放元素
我们需要一个提供hash函数的工具。写出一个行为类,重载()运算符。
class CalculateHashCode{public: std::size_t operator()(const string& str) { std::size_t n = 0; std::size_t nIndex = str.length(); while (nIndex) { n <<= 5; if ((--nIndex)& 1) { n += str[nIndex] * 3; } else { n ^= ((n >> 17) | 0x01) * str[nIndex]; } } return n; } std::size_t operator()(const wstring& str) { std::size_t n = 0; std::size_t nIndex = str.length(); while (nIndex) { n <<= 5; if ((--nIndex) & 1) { n += str[nIndex]; } else { n ^= ((n >> 17) | 0x01) * str[nIndex]; } } return n; } std::size_t operator()(const short& nNum) { return nNum; } std::size_t operator()(const unsigned short& nNum) { return nNum; } std::size_t operator()(const char& nNum) { return nNum; } std::size_t operator()(const unsigned char& nNum) { return nNum; } std::size_t operator()(const size_t& nNum) { return nNum; } std::size_t operator()(const int& nNum) { return nNum; } std::size_t operator()(const long long& nNum) { return (std::size_t)(nNum >> 31 ^ nNum); } std::size_t operator()(const unsigned long long& nNum) { return (std::size_t)(nNum >> 31 ^ nNum); } std::size_t operator()(const float& nNum) { return (std::size_t)(nNum * 50331653.333333f); } std::size_t operator()(const double& nNum) { return (std::size_t)(nNum * 50331653.333333); } std::size_t operator()(const long double& nNum) { return (std::size_t)(nNum * 50331653.333333); }};
- HashMap:
- hashMap应该是一个泛型容器,这里使用类模板来抽象数据类型。当然啦,也可以用void*来做出泛型。
template<typename Key, typename Value, typename CalcHash = CalculateHashCode>
三个类型参数名分别是元素的关键字,元素的内容值和计算hash的工具类型,这里我们默认为提供工具类型的是我们所写的计算hash类。
数据成员:
typedef struct _tagBucket { iterator _first; //list某一个桶的开始 iterator _last; //list某一个桶的最后一个元素 }Bucket; list<ValueType> _listValues; Bucket* _arrBuckets; std::size_t _nBucketSize; CalcHash _calcHash;
_listValues。使用标准库的双向链表来存放全部数据,为什么这样做呢?前面我们说过了当元素关键字冲突,计算到了一个被使用桶时候,这时候需要解决冲突问题,这里我们用将元素插入链表来解决,该方法称为链地址法。
_arrBuckets。 一个我们自定义的数据类型“Bucket”,我们只存放链表的区间范围的迭代器,这样就不需要为每一个桶都做一个链表,而是将每一个桶都想象为一个链表的某一个区间。
_nBucketSize。 桶的大小。
_calcHash。 计算hash值。
供外部使用的类型:
typedef typename pair<Key, Value> ValueType; typedef typename list<ValueType>::iterator iterator; typedef typename list<ValueType>::const_iterator const_iterator;
ValueType。标准库里,一对出现的元素都是用pair来解决的,我们也一样。
iterator。遍历链表元素。
const_iterator。遍历链表const元素。
内部方法:
我们将使用hash函数值的函数都是为私有的方法。
iterator find(const Key& k, std::size_t nHashCode); Value& at(const Key& k, std::size_t nHashCode); pair<iterator, bool> insert(const ValueType& v, std::size_t nHashCode); void erase(iterator it, std::size_t nHashCode); void reHashSize(std::size_t nHashBucketSize); static std::size_t hashSize(std::size_t nNumber);//静态函数
find方法:通过一个元素关键字来查找,需要一个hash值,成功返回元素迭代器,失败放回end迭代器。
at方法:通过一个元素关键字来查找,需要一个hash值,成功返回元素的内容,失败插入一个相同关键字并初始化内容的元素,然后返回元素的内容。
insert:插入一个元素,需要一个hash值。不允许重复关键字,成功返回该元素迭代器,bool值为true,失败返回end迭代器,bool值为false。
erase:该元素的迭代器,需要一个hash值(需要知道桶的位置)。
reHashSize:该容器可以扩容。需要一个桶的大小值。
hashSize:通过一个值,提供一个等于该值或者大于该值的值。(提供合适的值,提供素数是不错的办法)
供外部使用的方法:
HashMap() :_calcHash(CalcHash()), _listValues(), _nBucketSize(0), _arrBuckets(nullptr) { reHashSize(hashSize(1)); } HashMap(const CalcHash& func) :_calcHash(func), _listValues(), _nBucketSize(0), _arrBuckets(nullptr) { reHashSize(hashSize(1)); } HashMap(const HashMap<Key, Value, CalcHash>& hashMap) :_calcHash(hashMap._calcHash), _listValues(hashMap._listValues), _nBucketSize(0), _arrBuckets(nullptr) { reHashSize(hashSize(_listValues.size())); } HashMap(const initializer_list<ValueType>& list, const CalcHash& func = CalcHash()) :_calcHash(func), _listValues(list), _nBucketSize(0), _arrBuckets(nullptr) { reHashSize(hashSize(_listValues.size())); } ~HashMap() { if (_arrBuckets) delete[] _arrBuckets; } std::size_t BucketSize() { return _nBucketSize; } iterator begin() { return _listValues.begin(); } iterator end() { return _listValues.end(); } const_iterator cbegin() const { return _listValues.begin(); } const_iterator cend() const { return _listValues.end(); } bool empty() { return _listValues.empty(); } Value& at(const Key& k) { if ((_listValues.size()) >= (_nBucketSize << 1)) reHashSize(hashSize(_listValues.size())); return at(k, calcHashCode(k)); } HashMap<Key, Value, CalcHash>& operator<<(const ValueType& v) { at(v.first) = v.second; return *this; } Value& operator[](const Key& k) { return at(k); } iterator find(const Key& k) { return find(k, calcHashCode(k)); } void erase(iterator it) { erase(it, calcHashCode(it->first)); } void erase(const Key& k) { std::size_t nHashCode = calcHashCode(k); erase(find(k, nHashCode), nHashCode); } pair<iterator, bool> insert(const ValueType& v) { if ((_listValues.size()) >= (_nBucketSize << 1)) reHashSize(hashSize(_listValues.size())); return insert(v, calcHashCode(v.first)); } void clear() { _listValues.clear(); iterator end = _listValues.end(); for (size_t i = 0; i != num_buckets_; ++i) buckets_[i].first = buckets_[i].last = end; }
大家,都自己实现自己的HashMap吧!
- hashmap c
- hashmap C语言实现
- C语言实现HashMap
- c语言 ---- HashMap实现
- C语言hashmap
- [C++]HashMap实现STL map
- c.hashMap源码解析(1.7)
- 一个简单的HashMap C语言实现
- 一个简单的HashMap C语言实现
- c语言下的hashmap实现
- HashMap
- HashMap
- HashMap
- HashMap
- HashMap
- HashMap
- HashMap
- HashMap
- C++ map的基本操作和使用
- 监听webview显示完毕事件
- ubuntu上安装elasticsearch遇到的坑
- 关于自由移站法及坐标转换模型的综述
- SDUT 2054 双向链表
- C++ HashMap
- eclipse 基础设置
- Ajax验证表单(同步验证)
- Android Studio 开发常用快捷键
- csdn待改进点之3------>分类中的文章总数和实际总数不一致
- 如何判断外设使用的地址空间
- 怎么让eclipse控制器打印全部信息
- H-Index
- 数据库中主键和外键的设计原则/数据库事务的四种特性oracle