赞
踩
无序关联容器的底层是一个链式哈希表,包括下列四种:
无序关联容器 | 特点 |
---|---|
unordered_set | 无序集合,只存储key且不允许重复 |
unordered_multiset | 无序多重集合,只存储key且允许重复 |
unordered_map | 无序映射表,存储key-value且不允许重复 |
unordered_multimap | 无序多重映射表,存储key-value且允许重复 |
本程序实现了一个具有基础功能的unordered_map
// key-value类型 template<typename K, typename V> struct Pair { Pair(const K &k = K(), const V &v = V()) :first(k), second(v) {} K first; V second; }; //链式哈希表 template<typename K, typename V> class HashMap { public: HashMap(int size = 3, double loadFactor = 0.75) :mloadFactor(loadFactor),museBucketNum(0) { // 按照size开辟空间,并给vector添加size个list默认构造的容器 mhashMap.resize(size); } /** * 插入key-value对,如果插入的key存在,则用新的value将旧的value替换掉 * 在unordered_map中insert的返回类型为pair<iterator, bool>,但是由于尚未实现迭代器,故返回值类型为void */ void insert(const Pair<K, V> &pair) { double lf = museBucketNum * 1.0 / mhashMap.size(); // cout << "lf:" << lf << endl; if (lf > mloadFactor) // 扩容 { expand(); } // idx就是桶的下标 int idx = pair.first % mhashMap.size(); list<Pair<K, V>> &mylist = mhashMap[idx]; if (mylist.empty()) { museBucketNum++; } else { for (auto &item : mylist) { if (item.first == pair.first) { // key已经存在,不会重复插入 item.second = pair.second; return; } } } mylist.push_back(pair); } /** * 传入key,删除key-value对 */ void erase(const K &key) { // idx就是桶的下标 int idx = key % mhashMap.size(); auto &mylist = mhashMap[idx]; if (!mylist.empty()) { for (auto it = mylist.begin(); it != mylist.end(); ++it) { if (it->first == key) { mylist.erase(it); if (mylist.empty()) { // 删除后桶为空,更新已使用桶的数量 museBucketNum--; } return; } } } } /** * 传入key,返回包含key的key-value对的迭代器pair * 如果key不存在,返回nullptr */ Pair<K, V>* find(const K &key) { int idx = key % mhashMap.size(); list<Pair<K, V>> &mylist = mhashMap[idx]; if (!mylist.empty()) { for (auto &item : mylist) { if (item.first == key) { return &item; } } } return nullptr; } /** * operator[]的功能:增加一个[key, V()],然后把V()返回进行赋值操作、覆盖旧值、查询 * * 需要注意的是,map[key]当key不存在时会自动增加[key, V()],所以不建议使用operator[]查询,只做增加或者覆盖值使用 */ V& operator[](const K &key) { int idx = key % mhashMap.size(); list<Pair<K, V>> &mylist = mhashMap[idx]; if (mylist.empty()) { // 为一个空桶 museBucketNum++; } else { for (auto &item : mylist) { if (item.first == key) { return item.second; } } } // 插入时调用insert方法,这样新插入元素就会适时扩容哈希表 insert({ key, V() }); // 把mylist的尾结点的second返回(insert为尾插) return mylist.back().second; } private: vector<list<Pair<K, V>>> mhashMap; // 链式哈希表结构 double mloadFactor; // 加载因子 0.75 int museBucketNum; // 记录已经使用的桶的个数 /** * 判断是否为素数 * 素数的特性:恒等于 6x-1 或者 6x+1,其中 x 是大于等于1的自然数 * 由素数的特性可知:循环的步长可以设为 6,每次只判断 6 前后的两个数即可 */ bool isprime(int num) { // 判断是不是 6x 左右的数 if (num % 6 != 1 && num % 6 != 5) { return false; } int sq = (int)sqrt(num); for (int i = 5; i <= sq; i += 6) { if (num % i == 0 || num % (i+2) == 0) { return false; } } return true; } // 哈希表扩容函数 void expand() { vector<list<Pair<K, V>>> oldHashMap; // oldHashMap放的是旧哈希表的所有内容 mhashMap是空的 mhashMap.swap(oldHashMap); // 扩容后的哈希表的桶的个数设置为素数 int prime = oldHashMap.size() + 1; while (!isprime(prime)) { prime++; } mhashMap.resize(prime); museBucketNum = 0; // 遍历oldHashMap里面每一个不空的桶,把里面的list结点splice摘下来,放入新的哈希表mhashMap中 for (list<Pair<K, V>> &mylist : oldHashMap) { while (!mylist.empty()) { Pair<K, V> &pair = mylist.front(); int idx = pair.first % mhashMap.size(); list<Pair<K, V>> &newlist = mhashMap[idx]; if (newlist.empty()) { museBucketNum++; } newlist.splice(newlist.begin(), mylist, mylist.begin()); } } } }; // 测试代码 int main() { HashMap<int, string> map; map.insert({ 1010, "wu" }); map.insert({ 1020, "fan" }); map.insert({ 1030, "love" }); map.insert({ 1040, "yan" }); map.insert({ 1050, "han" }); cout << map[1030] << endl; //map.erase(1010); Pair<int, string> *it = map.find(1010); if (it == nullptr) { cout << "not find" << endl; } else { cout << it->first << endl; } return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。