C++的map介绍

C++的map介绍

关联式容器

​ 在数据结构的初级阶段, 我们使用了如: vector, list, deque这样的序列式容器. 之所以为序列式容器, 是因为他们的底层是线性序列的数据结构, 如我们讲到的deque, 底层就是分段的连续线性结构.

​ 那么说明时候关联式容器呢? 关联式同样也是存储数据的, 只不过他不是存放单一的数据, 而是存放的键值对. 这个和Python的字典是一样的. 这样的容器通常在数据检索的时候效率很高, 比序列式容器的检索快很多.

键值对

​ 用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息。比如:现在要建立一个英汉互译的字典,那该字典中必然有英文单词与其对应的中文含义,而且,英文单词与其中文含义是一一对应的关系,即通过该应该单词,在词典中就可以找到与其对应的中文含义。
SGI-STL中关于键值对的定义:

template <class T1, class T2>
struct pair
{
	typedef T1 first_type;
	typedef T2 second_type;
	T1 first;
	T2 second;
	pair(): first(T1()), second(T2())
	{}
	pair(const T1& a, const T2& b): first(a), second(b)
	{}
};

树形结构的关联式容器

​ 根据应用场景的不同, STL总共实现了两种不同结构的管理式容器: 树形结构和哈希结构. 树形结构主要有4种: map, set, multimap, multiset. 他们的共同点是: 底层都使用的是平衡搜索二叉树(红黑树), 容器内的元素都是一个有序的序列, 该篇博客主要讲解map.

快速熟悉map

map的概念

map的CPlusPlus文档.

​ 从文档中我们不难看出以下六点:

  1. map是关联容器, 它按照特点的次序(按照key来进行比较)存储由键key和值value组成的键值对.

  2. 在map内, key用于排序和惟一确定一个键值对, 而value则用于存放和key相关的内容. key和value的类型通常是不一样的. 在map内部, key和value通过成员类型value_type绑定, 取别名为pair.

    typedef pair<const key, T> value_type;
    
  3. 在map内, 总是按照key来进行排序的.

  4. map通过键值对来访问随机元素比unordered_map要慢, 但是map可以直接顺序迭代, 得到一个有序序列.

  5. map支持下标访问, 通过[key]来得到元素. 并且和Python的字典一样, 他可以通过下标来新增元素.

  6. map的底层为平衡搜索二叉树(红黑树).

map的基本使用

#include <iostream>
#include <string>
#include <set>
#include <map>

int main()
{
    std::map<std::string, int> map;
    // pair的使用不需要额外引头文件
    map.insert(std::pair<std::string, int>("pangchao", 123));
    map.insert(std::pair<std::string, int>("liqing", 456));
    map.insert(std::pair<std::string, int>("heqing", 789));
    map["wanger"] = 159;
    std::map<std::string, int>::iterator it = map.begin();
    while(it != map.end())
    {
        std::cout << it->first << ": " << it->second << std::endl;
        ++it;
    }
    std::cout << "size: " << map.size() << std::endl;
    std::cout << "empty: " << map.empty() << std::endl;

    return 0;
}

​ 运行结果如下, 可以看到map的使用和STL的其他容器使用起来非常像, 几个接口的名字都是一样的, 这得益于这种统一的思想.

[pangchao@VM-4-9-centos 230403]$ make clean;make
rm -f test
g++ test.cc -o test -std=c++11
[pangchao@VM-4-9-centos 230403]$ ./test 
heqing: 789
liqing: 456
pangchao: 123
wanger: 159
size: 4
empty: 0

两道OJ题

​ 接下来通过两道OJ题目来强化对map的了解.

  1. 692. 前K个高频单词 - 力扣(Leetcode).

    这里需要特别注意的是, 不可以直接对map进行排序, 原因是map没有重载"-"这个运算符, 我们只能借助中间者来进行排序, 如: vector.

    class Solution {
    public:
        vector<string> topKFrequent(vector<string>& words, int k) {
            unordered_map<string, int> dict;
            for (string& word : words)
            {
                if (dict.end() != dict.find(word))
                {
                    // 存在于dict中
                    ++dict[word];
                }
                else
                {
                    dict[word] = 1;
                }
            }
            // sort(dict.begin(), dict.end());
            // 没法对map进行直接排序的 只能借助vector
            vector<pair<string, int>> result(dict.begin(), dict.end());
            sort(result.begin(), result.end(), [](const pair<string, int>& a, const pair<string, int>& b) {
                if (a.second != b.second)
                return (a.second) > (b.second);
                else
                    return (a.first) < (b.first);
                });
            vector<string> tmp;
            vector<pair<string, int>>::iterator it = result.begin();
            while (k != 0 && it != result.end())
            {
                tmp.push_back(it->first);
                --k;
                ++it;
            }
            return tmp;
        }
    };
    
  2. 单词识别_牛客题霸_牛客网 (nowcoder.com).

    #include <iostream>
    #include <string>
    #include <algorithm>
    #include <vector>
    #include <set>
    #include <map>
    #include <unordered_map>
    
    int main() 
    {
    
        std::string source;
        std::getline(std::cin,source);
        // 1. 转化为小写 并且进行切分
        size_t left = 0;
        size_t right = 0;
        std::vector<std::string> tmp;
        while(right != source.length())
        {
            if(source[right] < 91 && source[right] > 64)
            {
                source[right] = source[right] + 32;
            }
            if(source[right] == ' ' || source[right] == '.')
            {
                tmp.push_back(source.substr(left, right - left));
                left = right + 1;
            }
            ++right;
        }
        // 2. 使用map进行排序
        std::map<std::string, int> dict;
        for (std::string& word : tmp)
        {
            if (dict.end() != dict.find(word))
            {
                // 存在于dict中
                ++dict[word];
            }
            else
            {
               dict[word] = 1;
            }
        }
        // sort(dict.begin(), dict.end());
        // 没法对map进行直接排序的 只能借助vector
        std::vector<std::pair<std::string, int>> result(dict.begin(), dict.end());
        std::sort(result.begin(), result.end(), [](const std::pair<std::string, int>& a, const std::pair<std::string, int>& b) {
            if (a.second != b.second)
                return (a.second) > (b.second);
            else
                return (a.first) < (b.first);
            });
        // 3. 打印
        for(const auto& item : result)
        {
            std::cout << item.first << ":" << item.second << std::endl;
        }
        return 0; 
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

roseisbule

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值