基于哈希的 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. vue中this在回调函数中的使用

    this在各类回调中使用: 如果是普通函数是没法使用的 所以需要先将this.变量赋值给新的变量,然后才能在回调函数中使用 例如: refund: function (id) { if (!this. ...

  2. centos7 字体库。vim乱码

    centos7 字体库.vim乱码 windows上传文件到centos,需要先使用dos2unix命令进行格式转换 先查看/usr/share下有没有这两个文件 没有的话yum -y install ...

  3. DNS | named.run文件很大的处理方法

    在查看/var/named/data目录中发现named.run文件260G+ 总用量 267G -rw-r--r-- 1 named named 1.3K 9月 2 21:27 named.run ...

  4. iMacros 入门教程-基础函数介绍(2)

    imacros 的 pos 参数是什么意思 position的缩写,如果有 2 个以上的元素共用完全相同的属性(比方说同一个小区的同一栋楼),这个 POS 的参数可以借由不同位置来帮助明确定位(也就是 ...

  5. 安装Nexus到Linux(源码)

    运行环境 系统版本:CentOS Linux release 7.4.1708 (Core) 软件版本:Sonatype-Nexus-3.14.0 硬件要求:无 安装过程 1. 调整系统参数 需要调整 ...

  6. CSS背景说明及连写

    一.CSS背景说明 CSS 可以添加背景颜色和背景图片,以及来进行图片设置. 1.1 背景图片(image) background-image 属性允许指定一个图片展示在背景中(只有CSS3才可以多背 ...

  7. PAT甲级代码仓库

    大道至简,知易行难.希望能够坚持刷题. PAT甲级真题题库,附上我的代码. Label Title Score Code Level 1001 A+B Format 20 1001 * 1002 A+ ...

  8. position定位及实际应用

    position: static;  静态定位 / 常规定位 / 自然定位 忽略top/right/bottom/left/z-index的影响,使元素回到自然流中 <!DOCTYPE html ...

  9. IE浏览器中IFrame被加载两次问题的解决-sunziren

    本文为作者sunziren原创,首发博客园,转载请注明出处. 昨天遇到了一个问题,先上代码. var content = '<iframe src="www.baidu.com&quo ...

  10. 常用 SQL Server 脚本

    运行维护 备份还原 # server_name # user_name # password # database_name # backup_path,备份路径,X:PathToBackupLoca ...