目录

【模板类】Map & Unordered_Map

Map & Unordered_map

Map使用红黑树组织数据,Unordered_map使用哈希表组织数据。

对于Map而言:

存储数据占用内存比哈希表更小,构造速度更快,但查找数据的速度更慢。构造函数只需要比较函数(less)。

查找对象的时间:$O(log{(n)})$

对于unordered_map而言:

占用内存比Map大,构造速度慢,但查找速度快。构造函数需要hash函数,等于函数(equal)。

查找对象的时间:近似为$O(1)$

map简介

map是STL的一个关联容器,它提供一对一的hash。

第一个可以称为关键字(key),每个关键字只能在map中出现一次; 第二个可能称为该关键字的值(value)

map以模板(泛型)方式实现,可以存储任意类型的数据,包括使用者自定义的数据类型。

Map主要用于资料 一对一映射(one-to-one) 的情況,map內部的实现自建一棵红黑树,这棵树具有对数据自动排序的功能。在map内部,所有的数据都是有序的。

对象初始化和成员函数

注意

使用map需要包含map类所在的头文件:

#include <map> //注意,STL头文件没有扩展名.h

对象初始化

map<键类型, 值类型> 标识符

键值对插入

插入键值对的方法有三种:

// 初始化
map<int, string> mapStudent;
// 第一种 用insert函數插入pair
mapStudent.insert(pair<int, string>(000, "student_zero"));
// 第二种 用insert函数插入value_type数据
mapStudent.insert(map<int, string>::value_type(001, "student_one"));
// 第三种 用"array"方式插入
mapStudent[002] = "student_two";

以上三种用法,虽然都可以实现数据的插入,但是它们是有区别的!

第一种和第二种在效果上是完成一样的,用insert函数插入数据,在数据的插入上涉及到集合的唯一性这个概念,即当map中有当前关键字时,insert操作是不能再插入数据的,但是用数组方式可以覆盖以前该关键字对应的值

成员函数

begin()返回指向map头部的迭代器

clear()删除所有元素

count()返回指定元素出现的次数

empty()如果map为空则返回true

end()返回指向map末尾的迭代器

equal_range()返回特殊条目的迭代器对

erase()删除一个元素

find()查找一个元素

get_allocator()返回map的配置器

insert()插入元素

key_comp()返回比较元素key的函数

lower_bound()返回键值>=给定元素的第一个位置

max_size()返回可以容纳的最大元素个数

rbegin()返回一个指向map尾部的逆向迭代器

rend()返回一个指向map头部的逆向迭代器

size()返回map中元素的个数

swap()交换两个map

upper_bound()返回键值>给定元素的第一个位置

value_comp()返回比较元素value的函数

unordered_map简介

unordered_map基于hash table(哈希表)。功能与map相似。

哈希表最大的优点,就是把数据的存储和查找消耗的时间大大降低,几乎可以看成是常数时间;而代价仅仅是消耗比较多的内存。然而在当前可利用内存越来越多的情况下,用空间换时间的做法是值得的。另外,编码比较容易也是它的特点之一。

其基本原理是:使用一个下标范围比较大的数组来存储元素。可以设计一个函数(哈希函数,也叫做散列函数),使得每个元素的关键字都与一个函数值(即数组下标,hash值)相对应,于是用这个数组单元来存储这个元素;也可以简单的理解为,按照关键字为每一个元素“分类”,然后将这个元素存储在相应“类”所对应的地方,称为桶。

但是,不能够保证每个元素的关键字与函数值是一一对应的,因此极有可能出现对于不同的元素,却计算出了相同的函数值,这样就产生了“冲突”,换句话说,就是把不同的元素分在了相同的“类”之中。

总的来说,“直接定址”与“解决冲突”是哈希表的两大特点。

对象初始化和成员函数

注意

使用unordered_map需要包含unordered_map类所在的头文件:

#include <unordered_map>

对象初始化

unordered_map<键类型, 值类型> 标识符;

成员函数

成员函数与map相似。

实战(49. Group Anagrams)

这一题的关键在于字母异位词排序后得到的字符串相同,可以用map记录每种字母异位词排序后的字符串的出现情况,并记录其存放在结果数组中的索引位置。

#include <algorithm>
#include <iostream>
#include <map>
#include <string>
#include <vector>
using namespace std;

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        map<string, int> count; // map记录每个字符串排序后字符串和在结果数组的索引
        vector<vector<string>> ans; // 结果数组
        int cur_index = 0; // 当前结果数组的长度
        for (int i = 0; i < strs.size(); i++) {
            string temp = strs[i];
            sort(temp.begin(), temp.end());
            if (count.count(temp)) { // map里有同款的字母异位词
                ans[count[temp]].push_back(strs[i]);
            } else { // map里没有当前同款的字母异位词
                count[temp] = cur_index;
                ans.push_back({strs[i]});
                cur_index++;
            }
        }
        return ans;
    }
};