基于哈希的 map 和 set

简述

基于哈希的 mapset ,它们分别叫做 unordered_map, unordered_set 。数据分布越平均,性能相较 mapset 来说提升就更大。但由于它们基于哈希,所以并不像 mapset 一样能自动排序;它们都是无序的。

我做了一个测试:随机生成 \(10^7\) 个 int 范围内的整数(平均分布),然后将其分别插入 mapunordered_map,再完整的做一次查询,查看时间和内存上的消耗。

测试代码

#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <map>
#include <vector>
#include <unordered_map> using namespace std; vector<pair<int, int>> data; int main() {
freopen("map.txt", "r", stdin);
data.resize(5000000);
map<int, int> mp;
double st, ed;
st = clock();
for (int i = 0; i < 5000000; ++i) scanf("%d%d", &data[i].first, &data[i].second);
ed = clock();
printf("Read: %dms\n", int(1000.0 * (ed - st) / CLOCKS_PER_SEC));
st = clock();
for (int i = 0; i < 5000000; ++i) mp[data[i].first] = data[i].second;
ed = clock();
printf("Insert: %dms\n", int(1000.0 * (ed - st) / CLOCKS_PER_SEC));
st = clock();
for (int i = 0; i < 5000000; ++i) data[i].second = mp[data[i].first];
ed = clock();
printf("Query: %dms\n", int(1000.0 * (ed - st) / CLOCKS_PER_SEC));
data = vector<pair<int, int>>();
}

测试结果

结构 总耗时 插入耗时 查询耗时 内存
map 18,041 MS 10,299 MS 7,742 MS 230.7 MB
unordered_map 7,138 MS 5,426 MS 1,712 MS 212.0 MB

当数据分布平均时,从时间上看,两者的性能差距约为 \(7138 / 18041 \approx 40\%\)

提示

即使在平均意义下 unordered_map 有着比 map 更高的效率,但是由于两者的实现(前者哈希,后者平衡树), unordered_map 单次插入的最差复杂度是 \(O(N)\), map 单次插入的最差复杂度是 \(O(log N)\) 。所以在出题人故意造数据卡 unordered_map 使其内部哈希表发生严重冲突时,unordered_map 就会变得很慢。

语法上的变化

auto 关键字的新含义

在 C++11 中,auto 关键字被赋予了新的含义。其功能是自动类型推导。

auto x = 3; // y的类型自动推导为 int
auto y = make_pair(1, 2); // y的类型自动推导为 pair<int, int>
auto z; // 编译错误, z的类型需要一个初始值才能推导 map<int, int> mp;
// iter的类型推导为map<int, int>::iterator
for (auto iter = mp.begin(); iter != mp.end(); ++iter)
cout << iter->first << ' ' << iter->second << '\n';

与其相关的是一个新的关键字 decltype,取得某一个值的类型。

int a = 1, b = 2;
decltype(a + b) c; // c为int

增强的 for(基于范围的for循环)

map<int, int> mp;

// C++11 之前遍历
for (map<int, int>::iterator it = mp,begin(); it != mp,end(); ++it)
cout << it->first << ' ' << it->second << '\n'; // C++11 之后
for (auto val : mp)
cout << val.first << ' ' << val.second << '\n';

模板嵌套时一个小改善

priority_queue<pair<int, int> > heap; // C++11之前需加一个空格避免歧义
priority_queue<pair<int, int>> heap; // C++11之后不用

初始化列表

更简单的初始化方式。

vector<pair<int, int>> v{ {1, 2}, {2, 3}, {3, 4} };

// 等价于下面代码
vector<pair<int, int> > v;
v.push_back(make_pair(1, 2));
v.push_back(make_pair(2, 3));
v.push_back(make_pair(3, 4));

lambda 表达式

下面用一个例子讲述一下lambda表达式的大致用法。

#include <iostream>
#include <vector>
#include <algorithm> using namespace std; int main() {
vector<pair<int, int>> v{ {1, 2}, {2, 3}, {3, 4} };
for (auto& val : v) {
cout << val.first << ' ' << val.second << '\n';
}
sort(v.begin(), v.end(), [](const pair<int, int> &a, const pair<int, int> &b) {
return a.first > b.first;
});
cout << "After sort:\n";
for (auto& val : v) {
cout << val.first << ' ' << val.second << '\n';
}
return 0;
}

代码里的 sort,在C++11之前比较常见的等价写法是:

bool cmp(const pair<int, int> &a, const pair<int, int> &b) {
return a.first > b.first;
} int main() {
// ...
sort(v.begin(), v.end(), cmp);
// ...
}

C++11 新用法的更多相关文章

  1. C++11之for循环的新用法《转》

    相关资料:https://legacy.gitbook.com/book/changkun/cpp1x-tutorial/details C++11之for循环的新用法 C++使用如下方法遍历一个容器 ...

  2. C++11常用特性介绍——for循环新用法

    一.for循环新用法——基于范围的for循环 for(元素类型 元素对象 : 容器对象) { //遍历 } 1)遍历字符串 std::string str = "hello world&qu ...

  3. C++ 11学习和掌握 ——《深入理解C++ 11:C++11新特性解析和应用》读书笔记(一)

    因为偶然的机会,在图书馆看到<深入理解C++ 11:C++11新特性解析和应用>这本书,大致扫下,受益匪浅,就果断借出来,对于其中的部分内容进行详读并亲自编程测试相关代码,也就有了整理写出 ...

  4. [转载] C++11新特性

    C++11标准发布已有一段时间了, 维基百科上有对C++11新标准的变化和C++11新特性介绍的文章. 我是一名C++程序员,非常想了解一下C++11. 英文版的维基百科看起来非常费劲,而中文版维基百 ...

  5. c++11新标准for循环和lambda表达式

    :first-child { margin-top: 0px; } .markdown-preview:not([data-use-github-style]) h1, .markdown-previ ...

  6. C++11新特性之一——Lambda表达式

    C++11新特性总结可以参考:http://www.cnblogs.com/pzhfei/archive/2013/03/02/CPP_new_feature.html#section_6.8 C++ ...

  7. C++11新标准:nullptr关键字

    一.nullptr的意义 1.NULL在C中的定义 #define NULL (void*)0 2.NULL在C++中的定义 #ifndef NULL #ifdef __cplusplus #defi ...

  8. C++11新标准:decltype关键字

    一.decltype意义 有时我们希望从表达式的类型推断出要定义的变量类型,但是不想用该表达式的值初始化变量(如果要初始化就用auto了).为了满足这一需求,C++11新标准引入了decltype类型 ...

  9. C++11新标准:auto关键字

    一.auto意义 编程时常常需要把表达式的值赋给变量,这就要求在声明变量的时候清楚地知道表达式的类型,然后要做到这一点并非那么容易.为了解决这个问题,C++11新标准引入了auto类型说明符,用它就能 ...

随机推荐

  1. 使用UCSC Genome Browser下载人类所有mRNA序列

    打开UCSC Genome Browser官网.网址:http://genome.ucsc.edu/ 点击导航栏的Genome Data 在新的页面中,点击human,可快速定位至页面中人类基因组数据 ...

  2. P3983 赛斯石(赛后强化版)

    链接:Miku ------------- 题目描述一脸懵逼 ------------ 这道题本质上是两个完全背包而已.首先,对于每个船,他所能装的最大货物价值是一定的, 我们可以跑完全背包求出每艘船 ...

  3. 安装MongoDB到Ubuntu(APT)

    运行环境 系统版本:Ubuntu 16.04.5 LTS 软件版本:mongodb-org-4.0.8 硬件要求:无 安装过程 1.配置APT-Mongodb存储库 ATP-Mongodb存储库由Mo ...

  4. spawn id exp6 not open

    原因 脚本没有被执行 解决方案 手动执行该条命令参看报错的原因

  5. PP: Unsupervised anomaly detection via variational auto-encoder for seasonal KPIs in web applications

    Problem: unsupervised anomaly detection for seasonal KPIs in web applications. Donut: an unsupervise ...

  6. ARM微处理器中支持字节、半字、字三种数据类型,地址的低两位为0是啥意思?

    问题: ARM微处理器中支持字节.半字.字三种数据类型,其中,字需要4字节对齐(地址的低两位为0).半字需要2字节对齐(地址的最低位为0).我想问的是括号中的内容是什么意思呢?请牛人帮忙解释一下!谢谢 ...

  7. MySQL int、char、varchar 最大值是多少?

    1.int(len) (1)max(len) = 255 (2)存储范围: 带符号整数:-2147483648-2147483647. 无符号(unsigned)整数:0-4294967295. 2. ...

  8. BZOJ 4247: 挂饰 动态规划

    按照挂件数量排序,然后做一个 DP 就好了. code: #include <bits/stdc++.h> #define ll long long #define N 2003 #def ...

  9. gulp常用插件之gulp-rev-delete-origina使用

    更多gulp常用插件使用请访问:gulp常用插件汇总 gulp-rev-delete-origina这是一款删除由gulp-rev或 gulp-rev-all重写的原始文件 . 更多使用文档请点击访问 ...

  10. Linux 基础操作命令

    关机和注销 shutdown -h now 立刻关机 shutdown -r now 立刻重启 shutdown -h + 1分钟后关机(重启同样用法) shutdown -h : 11点钟关机(重启 ...