unordered_map 容器介绍

201 阅读3分钟

前言

作者对于 unordered_map 是一位 beginner.本文对于unordered_map的常用的crud 基本操作,用于供作者回忆和读者学习.

介绍

  • unordered_map 是一个key和value 的关联式容器,可以高效的根据key值查找对应的value。
  • key 应该是唯一的,key 和 value 的数据类型可以不相同。
  • unordered_map 查询单个 key 值的效率比map高,但是查询一定范围内的key值时效率比map
  • unordered_map 是无序的,map是有序的。
  • unordered_map 重载了 [] , 可以直接通过 [key] 找到value.

常用操作介绍

主要介绍curd,以及其他好用的函数。

插入元素

// 插入方法 1
un_mp.insert(std::unordered_map<std::string , int>::value_type("test" , 1));
// 插入方法 2
un_mp["test"] = 333;
    
std::cout << un_mp["test"] << '\n';

明显我们发现第二种插入方法更加的方便 un_map[key] = value

删除元素

un_mp["test"] = 333;
un_mp.erase("test");

std::cout << un_mp["test"] << '\n';

image.png 因为我们将 "test" 删除了 ,所以输出的是 0.

注: 如果删除的key 不存在的话 ,那么erase 函数会返回 0 , 其中返回值表示的是删除元素的个数

查询元素

auto f = un_mp.find("test");
if (f != un_mp.end())
    std::cout << f -> second << '\n';

返回的是迭代器的指针 , 如果不存在的话返回 un_map.end()

修改元素

这里推荐的指正修改和 [] 运算符直接修改

  • 第一个指针修改
    auto f = un_mp.find("test");
    std::cout << f -> second << '\n';
    
  • 第二个 [] 运算符修改
    un_mp["test"] = 333;  通过key修改value
    

遍历集合

un_mp["s"] = 1;
un_mp["ss"] = 2;
un_mp["sss"] = 3;
un_mp["ssss"] = 4;

for (auto x : un_mp)
    std::cout << x.second << ' ';

防被卡hash

很多比赛都会针对unordered_mapunordered\_mapunordered_setunordered\_set 的底层hash值 , 来造数据 ,导致对于单次的查询为O(n)O(n) , 而不是 O(1)O(1)的 , 所以可能对于n个元素的插入,再查询可能是O(n2)O(n ^ 2) , 导致超时。 所以给出一种防被卡的方法

struct custom_hash {
    static LL splitmix64(LL x) {
        x ^= x << 13;
        x ^= x >> 7;
        x ^= x << 17;
        return x; 
    }
    size_t operator () (LL x) const {
        static const LL FIXED_RANDOM = std::chrono::steady_clock::now().time_since_epoch().count(); // 时间戳
        return splitmix64(x + FIXED_RANDOM);
    }
};

可以这么定义

std::unordered_map<LL, bool, custom_hash> safe_map;

注意: 对于hash函数如果是std::string作为keystd::string 作为key的话 , 只需要将字符串hash成数值,再进行以上操作 , 修改 重载的 ()LL---->std::string

补充std::multimapstd::multimap

插入元素(不支持 [] 运算符)

mp.insert(std::make_pair(2 , 1));

删除键对应一个值

// 匹配键的值
mp.erase(2);

删除指定键的元素

auto it = mp.find(2); // 删除迭代器指向的元素
if (it != mp.end()) { 
    mp.erase(it); 
}

map 和 unordered_map 的区别

map
  • 头文件 : 引入头文件 include<map>
  • 优点有序性,这是map结构最大的优点,其元素的有序性在很多应用中都会简化很多的操作。红黑树,内部实现一个红黑书使得map的很多操作在lgn的时间复杂度下就可以实现,因此效率非常的高。
  • 缺点:空间占用率高,因为map内部实现了红黑树,虽然提高了运行效率,但是因为每一个节点都需要额外保存父节点,孩子节点以及红/黑性质,使得每一个节点都占用大量的空间
  • 适用处:对于那些有顺序要求的问题,用map会更高效一些。
unordered_map
  • 头文件:引入头文件 include<unordered_map>
  • 优点:内部实现了哈希表,因此其查找速度是常量级别的。
  • 缺点:哈希表的建立比较耗费时间
  • 适用处:对于查找问题,unordered_map会更加高效一些,因此遇到查找问题,常会考虑一下用unordered_map

:对于map 和 unordered_map 的区别 , 我实在不清楚, 所以我直接copy的大佬的。如果大家感兴趣,在下方点击链接可以查看。

参考文献: C++中的unordered_map用法详解-CSDN博客