从C语言到C++_26(set+map+multiset+multimap)力扣692+349+牛客_单词识别

目录

1. 关联式容器

1.1 树形结构的关联式容器

2. set的相关介绍

2.1 set的构造和迭代器

2.2 set的容量和操作函数

2.3 set使用代码

2.4 multiset使用

3. map的相关介绍

3.1 键值对

3.2 map的构造和迭代器

3.3 map的容量和操作函数

3.4 map使用代码

3.5 multimap使用

4. 笔试OJ题

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

priority_queue解析代码:

sort解析代码:

stable_sort解析代码:

multimap解析代码:

349. 两个数组的交集 - 力扣(LeetCode)

set解析代码:

单词识别_牛客题霸_牛客网 (nowcoder.com)

set解析代码:

multimap解析代码:

5. 笔试选择题

答案:

本篇完。


1. 关联式容器

我们已经接触过STL中的部分容器,比如:vector、list、deque、这些容器统称为序列式容器,

因为其底层为线性序列的数据结构,里面存储的是元素本身,

关联式容器也是用来存储数据的,与序列式容器不同的是,

其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高。

总结:
1、容器本身底层采用线性序列存储数据的结构叫做序列式容器,比如vector、list
2、容器本身底层采用键值对存储数据的结构叫做关联式容器,比如map、set

1.1 树形结构的关联式容器

根据应用场景的不同,STL总共实现了两种不同结构的管理式容器:树型结构与哈希结构。

树型结构的关联式容器主要有四种:map、set、multimap、multiset。

这四种容器的共同点是:底层实现为红黑树。

容器中的元素是一个有序的序列。下面一依次介绍每一个容器。


2. set的相关介绍

1. set是按照一定次序存储元素的容器
2. 在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。
3. 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序。
4. set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对子集进行直接迭代。
5. set底层实现为红黑树。

 注意:
1. 与map / multimap不同,map / multimap中存储的是真正的键值对<key, value>,set中只放
value,但在底层实际存放的是由<value, value>构成的键值对。
2. set中插入元素时,只需要插入value即可,不需要构造键值对。
3. set中的元素不可以重复(因此可以使用set进行去重)。
4. 使用set的迭代器遍历set中的元素,可以得到有序序列。
5. set中的元素默认按照小于来比较。
6. set中查找某个元素,时间复杂度为:O(logN)。
7. set中的元素不允许修改。


2.1 set的构造和迭代器


2.2 set的容量和操作函数


2.3 set使用代码

#include <iostream>
#include <set>
#include <map>
#include <functional>
using namespace std;

void test_set()
{
	//set<int> s;
	//s.insert(4);
	//s.insert(2);
	//s.insert(1);

	//set<int> s = { 1, 2, 1, 6, 3, 8, 5 }; C++11

	int arr[] = { 1, 2, 1, 6, 3, 8, 5 };
	set<int> s(arr, arr + sizeof(arr) / sizeof(arr[0]));
	//set<int, greater<int>> s(arr, arr + sizeof(arr) / sizeof(arr[0]));

	// 排序 + 去重
	set<int>::iterator it = s.begin();
	while (it != s.end())
	{
		//*it = 10; // 和前面二叉搜索树一样不能修改
		cout << *it << " ";
		++it;
	}
	cout << endl;

	for (const auto& e : s)
	{
		cout << e << " ";
	}
	cout << endl;
	cout << "size = " << s.size() << endl;

	s.erase(2);
	s.erase(30); // 直接用erase,没有删除的元素什么事都没
	for (const auto& e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	set<int>::iterator pos = s.find(20); // 用find删除,要判断,不然崩溃
	if (pos != s.end())
	{
		s.erase(pos);
	}
	pos = s.find(8); // 用find删除,要判断,不然崩溃
	if (pos != s.end())
	{
		s.erase(pos);
	}

	for (const auto& e : s)
	{
		cout << e << " ";
	}
	cout << endl;
	cout << "size = " << s.size() << endl;
	cout << s.empty() << endl;
}

int main()
{
	test_set();
	
	return 0;
}


2.4 multiset使用

set是不允许的键值冗余的,而multiset是允许键值冗余的,也就这个区别而已:

void test_multiset()
{
	int arr[] = { 1, 2, 1, 6, 3, 8, 5, 3, 3 };
	multiset<int> ms(arr, arr + sizeof(arr) / sizeof(arr[0]));
	for (const auto& e : ms)
	{
		cout << e << " ";
	}
	cout << endl;
	cout << ms.count(1) << endl; // set也有这个接口,是为了和multiset一致,在set中可以用来找元素在不在

	// find时,如果有多个值,返回中序的第一个
	auto pos = ms.find(3);
	while (pos != ms.end())
	{
		cout << *pos << " ";
		++pos; // ++是+到中序的下一个
	}
	cout << endl;

	ms.erase(3); // 删除所有的3
	for (const auto& e : ms)
	{
		cout << e << " ";
	}
	cout << endl;

	pos = ms.find(1); // 删除一个1
	if (pos != ms.end())
	{
		ms.erase(pos);
	}
	for (const auto& e : ms)
	{
		cout << e << " ";
	}
	cout << endl;
}

int main()
{
	//test_set();
	test_multiset();
	
	return 0;
}


3. map的相关介绍

 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允许根据顺序对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。
5. map支持下标访问符,即在[ ]中放入key,就可以找到与key对应的value。
6. map底层实现为红黑树。


3.1 键值对

map中存储的键值对介绍:

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量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)
	{}
};

常用的:


3.2 map的构造和迭代器

 

key: 键值对中key的类型。

T: 键值对中value的类型。

Compare : 比较器的类型,map中的元素是按照key来比较的,缺省情况下按照小于来比较,

一般情况下(内置类型元素)该参数不需要传递,如果无法比较时(自定义类型),

需要用户自己显式传递比较规则(一般情况下按照函数指针或者仿函数来传递)。

Alloc:通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库提供的空间配置器。

注意:在使用map时,需要包含头文件#include <map>,键值对的头文件也在里面了。 


3.3 map的容量和操作函数

方括号是map的很特别的操作,其它不是连续空间存储的都没有,但是map的方括号和普通的也不一样,它返回的是键值对中key对应的value的引用。

当key不在map中时,通过operator[ ] 获取对应value时会发生什么问题?

 在元素访问时,有一个与operator[ ]类似的操作:at()函数(该函数不常用),都是通过key找到与key对应的value然后返回其引用,

不同的是:当key不存在时,operator[ ]用默认value与key构造键值对然后插入,返回该默认value,at()函数直接抛异常。

上面方括号调用的那句代码分成两句就是这样:


3.4 map使用代码

用map来创建字典:

void test_map1()
{
	map<string, string> dict;
	//pair<string, string> kv1("sort", "排序");
	//dict.insert(kv1);

	dict.insert(pair<string, string>("sort", "排序")); // 等价于上面注释
	dict.insert(pair<string, string>("test", "测试"));
	dict.insert(pair<string, string>("string", "字符串"));
	typedef pair<string, string> DictKV;
	dict.insert(DictKV("string", "xxx"));
	dict.insert(make_pair("left", "左边")); // 常用这种插入
	dict["right"] = "右边"; // 更常用这种插入

	//map<string, string>::iterator it = dict.begin();
	auto it = dict.begin(); // 等价于上面注释
	while (it != dict.end())
	{
		//cout << (*it).first << (*it).second <<endl;
		cout << it->first << ":" << it->second << endl; // 等价于上面注释
		++it;
	}
	cout << endl;

	for (const auto& kv : dict)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
	cout << endl;
}

int main()
{
	//test_set();
	//test_multiset();
	test_map1();

	return 0;
}


用map来计算次数:

void test_map2()
{
	string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
	//map<string, int> countMap;
	//for (const auto& str : arr)
	//{
	//	map<string, int>::iterator it = countMap.find(str);
	//	if (it != countMap.end())
	//	{
	//		//(*it).second++;
	//		it->second++;
	//	}
	//	else
	//	{
	//		countMap.insert(make_pair(str, 1));
	//	}
	//}
	map<string, int> countMap;
	for (const auto& str : arr) // 等同于上面一大段注释
	{
		// 1、str不在countMap中,插入pair(str, int()),然后在对返回次数++
		// 2、str在countMap中,返回value(次数)的引用,次数++;
		countMap[str]++;
	}

	map<string, int>::iterator it = countMap.begin();
	while (it != countMap.end())
	{
		cout << it->first << ":" << it->second << endl;
		++it;
	}
	cout << endl;
}

int main()
{
	//test_set();
	//test_multiset();
	//test_map1();
	test_map2();

	return 0;
}


3.5 multimap使用

multimap和multiset一样是允许键值冗余的,

1. multimap是关联式容器,它按照特定的顺序,存储由key和value映射成的键值对<key,value>,其中多个键值对之间的key是可以重复的。
2. 在multimap中,通常按照key排序和惟一地标识元素,而映射的value存储与key关联的内容。key和value的类型可能不同,通过multimap内部的成员类型value_type组合在一起,value_type是组合key和value的键值对 :typedef pair<const Key, T> value_type;
3. 在内部,multimap中的元素总是通过其内部比较对象,按照指定的特定严格弱排序标准对key进行排序的。
4. multimap通过key访问单个元素的速度通常比unordered_multimap容器慢,但是使用迭代器直接遍历multimap中的元素可以得到关于key有序的序列。
5. multimap在底层用二叉搜索树(红黑树)来实现。
注意:multimap和map的唯一不同就是:map中的key是唯一的,而multimap中key是可以重复的。

multimap中的接口可以参考map,功能都是类似的。
注意:
1. multimap中的key是可以重复的。
2. multimap中的元素默认将key按照小于来比较
3. multimap中没有重载operator[ ]操作。
4. 使用时与map包含的头文件相同。

void test_multimap()
{
	map<string, string> dict;
	dict.insert(make_pair("sort", "排序"));
	dict["insert"];
	dict["insert"] = "插入";
	dict["left"] = "左边";
	dict["left"] = "左边";
	for (const auto& kv : dict)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
	cout << dict.size() << endl;

	multimap<string, string> mdict;
	mdict.insert(make_pair("sort", "排序"));
	mdict.insert(make_pair("right", "右边"));
	mdict.insert(make_pair("right", "正确"));
	mdict.insert(make_pair("right", "右边")); // 正常插入,不管key值
	for (const auto& kv : mdict)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
	cout << mdict.size() << endl;
}

int main()
{
	//test_set();
	//test_multiset();
	//test_map1();
	//test_map2();
	test_multimap();

	return 0;
}


4. 笔试OJ题

set和map在很多统计次数的OJ中都能用,这里先写两道:

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

难度中等

给定一个单词列表 words 和一个整数 k ,返回前 k 个出现次数最多的单词。

返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率, 按字典顺序 排序。

示例 1:

输入: words = ["i", "love", "leetcode", "i", "love", "coding"], k = 2
输出: ["i", "love"]
解析: "i" 和 "love" 为出现次数最多的两个单词,均为2次。
    注意,按字母顺序 "i" 在 "love" 之前。

示例 2:

输入: ["the", "day", "is", "sunny", "the", "the", "the", "sunny", "is", "is"], k = 4
输出: ["the", "is", "sunny", "day"]
解析: "the", "is", "sunny" 和 "day" 是出现次数最多的四个单词,
    出现次数依次为 4, 3, 2 和 1 次。

注意:

  • 1 <= words.length <= 500
  • 1 <= words[i] <= 10
  • words[i] 由小写英文字母组成。
  • k 的取值范围是 [1, 不同 words[i] 的数量]

进阶:尝试以 O(n log k) 时间复杂度和 O(n) 空间复杂度解决。

class Solution {
public:
    vector<string> topKFrequent(vector<string>& words, int k) {

    }
};

priority_queue解析代码:

这道题是topk问题和统计次数的融合,就是先排次数(val)多的k个,次数一样多的按key排降序,

map里面是不管key的,这样我们就要写一个排序的仿函数了,先用优先级队列(堆)写一写:

优先级队列默认大的优先级高,传的是 less 仿函数,底层是一个大堆;

如果想控制小的优先级高,需手动传 greater 仿函数,其底层是一个小堆。

我们要弄一个大堆,大堆key一样的时候,按val弄一个小堆:

class Solution {
public:
    struct Less
    {
        bool operator()(const pair<string,int>& kv1,const pair<string,int>& kv2) const
        {
            if(kv1.second < kv2.second) // second(int)升序,小的在前面就ture
            {
                return true;
            }
            if(kv1.second == kv2.second && kv1.first > kv2.first) // first(string)降序
            {
                return true;
            }
            return false;
        }
    };

    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string,int> countMap;
        for(const auto& str : words) // 统计次数
        {
            countMap[str]++;
        }

        /*priority_queue<pair<string,int>,vector<pair<string,int>>,Less> MaxHeap;
        for(const auto& kv : countMap) // 也可以迭代器区间初始化,就是太长了,长就typedef
        {
            MaxHeap.push(kv);
        }*/
        typedef priority_queue<pair<string,int>,vector<pair<string,int>>,Less> MaxHeapType;
        MaxHeapType MaxHeap(countMap.begin(),countMap.end());

        vector<string> v;
        while(k--)
        {
            v.push_back(MaxHeap.top().first);
            MaxHeap.pop();
        }
        return v;
    }
};

sort解析代码:

在上面的基础上想想,如果我们用一个稳定的排序来排序string,是不是就能解决?

虽然sort不能排序map,但是可以把map转移到vector里然后在sort,直接sort是不稳定的,

但我们可以控制仿函数来间接控制:

(下面几种方法已经不是为了解题了,只是为了熟悉各个方法的使用,

因为priority的仿函数是反过来的,这里只需改下仿函数的大于小于号,把Less改成Great:)

class Solution {
public:
    struct Great
    {
        bool operator()(const pair<string,int>& kv1,const pair<string,int>& kv2) const
        {
            if(kv1.second > kv2.second)
            {
                return true;
            }
            if(kv1.second == kv2.second && kv1.first < kv2.first)
            {
                return true;
            }
            return false;
        }
    };

    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string,int> countMap;
        for(const auto& str : words) // 统计次数
        {
            countMap[str]++;
        }

        vector<pair<string,int>> sortV(countMap.begin(),countMap.end());
        sort(sortV.begin(),sortV.end(),Great());

        vector<string> v;
        for(int i = 0; i < k; ++i)
        {
            v.push_back(sortV[i].first);
        }
        return v;
    }
};

stable_sort解析代码:

幸运的是algorithm里面有一个stable_sort,它是基于归并排序实现的,是稳定的,也就是仿函数里少写了一段:(下面代码stable_sort换成sort就不行)

class Solution {
public:
    struct Great
    {
        bool operator()(const pair<string,int>& kv1,const pair<string,int>& kv2) const
        {
            if(kv1.second > kv2.second) // 次数大的在前面
            {
                return true;
            }
            /*if(kv1.second == kv2.second && kv1.first < kv2.first)
            {
                return true;
            }*/
            return false;
        }
    };

    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string,int> countMap;
        for(const auto& str : words) // 统计次数
        {
            countMap[str]++;
        }

        vector<pair<string,int>> sortV(countMap.begin(),countMap.end());
        stable_sort(sortV.begin(),sortV.end(),Great());

        vector<string> v;
        for(int i = 0; i < k; ++i)
        {
            v.push_back(sortV[i].first);
        }
        return v;
    }
};

multimap解析代码:

这里可以用multimap 代替stable_sort 以用来排序,可以直接用库里的仿函数:

class Solution {
public:
    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string, int> countMap;
        for(const auto& str : words) // 统计次数
        {
            countMap[str]++;
        }

        multimap<int, string, greater<int>> sortMap;
        for(const auto& kv : countMap)
        {
            sortMap.insert(make_pair(kv.second,kv.first));
        }

        vector<string> v;
        multimap<int, string, greater<int>>::iterator it = sortMap.begin();
        for(int i = 0; i < k; ++i)
        {
            v.push_back(it->second);
            ++it;
        }
        return v;
    }
};

349. 两个数组的交集 - 力扣(LeetCode)

难度简单

给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。

示例 1:

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]

示例 2:

输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
解释:[4,9] 也是可通过的

提示:

  • 1 <= nums1.length, nums2.length <= 1000
  • 0 <= nums1[i], nums2[i] <= 1000
class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {

    }
};

set解析代码:

如果两个数组是有序的,则可以使用双指针的方法得到两个数组的交集。

这里还需要去重,(库里还有一个去重的函数unique,加上sort也可以解决这题)

unique是不改变size的,所以很麻烦,用set(排序+去重)就是很好的选择: 

两个指针分别指向两个数组的头部。每次比较两个指针指向的两个数组中的数字,

如果两个数字不相等,则将指向较小数字的指针右移一位,如果两个数字相等,

输出到vector,然后两个指针右移。当至少有一个指针超出数组范围时,遍历结束。

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        set<int> s1(nums1.begin(),nums1.end());
        set<int> s2(nums2.begin(),nums2.end());

        set<int>::iterator it1 = s1.begin();
        auto it2 = s2.begin();

        vector<int> v;
        while(it1 != s1.end() && it2 != s2.end())
        {
            if(*it1 > *it2)
            {
                ++it2;
            }
            else if(*it1 < *it2)
            {
                ++it1;
            }
            else
            {
                v.push_back(*it1); // 相等,进哪个都行
                ++it1;
                ++it2;
            }
        }
        return v;
    }
};

单词识别_牛客题霸_牛客网 (nowcoder.com)

中等  通过率:22.37%  时间限制:1秒  空间限制:32M

知识点 字符串 哈希

描述

输入一个英文句子,把句子中的单词(不区分大小写)按出现次数按从多到少把单词和次数在屏幕上输出来,次数一样的按照单词小写的字典序排序输出,要求能识别英文单词和句号。

输入描述:

输入为一行,由若干个单词和句号组成

输出描述:

输出格式参见样例。

示例1

输入:

A blockhouse is a small castle that has four openings through which to shoot.

输出:

a:2
blockhouse:1
castle:1
four:1
has:1
is:1
openings:1
shoot:1
small:1
that:1
through:1
to:1
which:1
#include <iostream>
using namespace std;

int main() {
    int a, b;
    while (cin >> a >> b) { // 注意 while 处理多个 case
        cout << a + b << endl;
    }
}
// 64 位输出请用 printf("%lld")

set解析代码:

 1. 遍历语句字符串,从语句字符串中分离出单词

 2. 每分离出一个单词,就将该单词插入到map中,map会自动统计该单词出现的次数

 3. 将统计到的结果按照要求排序

 4. 输出

 注意:1. 统计单词时,要将单词的大小写统一,因为题目说不区分大小写,注意循环输入

      2. 利用set将统计的结果按照次数由大到小排序,如果次数一样按照字典序排序

      3. 输出排序之后的结果

#include <iostream>
using namespace std;
#include <map>
#include <set>

class Compare
{
public:
    bool operator()(const pair<string,int>& left, const pair<string,int>& right)
    {
        // 次数从大到小排序,如果次数相同,再按照单词字典序排序
        return left.second > right.second || left.first < right.first;
    }
};

int main()
{
    string s;
    while(getline(cin, s))
    {
        map<string, int> m;
        string temp;
        
        // 分割单词,采用map统计每个单词出现的次数
        for(size_t i = 0; i < s.size(); ++i)
        {
            if(s[i] == ' ' || s[i] == '.')
            {
                if(temp != "")// 一个单词解析结束
                {
                    m[temp]++;
                }
                temp = "";
            }
            else
            {
                temp += tolower(s[i]); // 题目说不区分大小写
            }
        }
        
        set<pair<string,int>, Compare> s;
        // 将map中的<单词,次数>放到set中,并按照次数升序,次数相同按照字典序规则排序
        for(auto& e : m)
        {
            s.insert(e);
        }
        for(auto& e : s) // 将统计到的结果按照要求输出
        {
            cout<<e.first<<":"<<e.second<<endl;
        }
    }
    return 0;
}

multimap解析代码:

#include <iostream>
#include <string>
#include <map>
#include <functional>
using namespace std;

int main() 
{
    string str;
    map<string, int> countMap;
    while(getline(cin,str))
    {
        for(int i=0,j=0;i<str.size();i++)
        {
            if(str[i]==' '||str[i]=='.')
            {
                string t=str.substr(j,i-j);
                if(isupper(t[0]))
                {
                    t[0]=tolower(t[0]);
                }
                j=i+1;
                countMap[t]++;
            }
        }
    }

    multimap<int, string, greater<int>> sortMap;
    for(const auto& kv : countMap)
    {
        sortMap.insert(make_pair(kv.second,kv.first));
    }

    for(const auto& kv : sortMap)
    {
        cout << kv.second << ":" << kv.first << endl;
    }

    return 0;
}

5. 笔试选择题

1. 下列说法正确的是()

A.set中的某个元素值不能被直接修改

B.map和unordered_map都是C++11提供的关联式容器

C.因为map和set的底层数据结构相同,因此在实现时set底层实际存储的是<key, key>的键值对

D.map和multimap中都重载了[]运算符

2.下面关于set的说法正确的是()

A.set中一定不能存储键值对,只能存储key

B.set可以将序列中重复性的元素去除掉

C.set中不能存储对象,因为对象字段较多,没有办法比较

D.set默认是升序,因为其默认是按照大于的方式比较的

3. 下面关于map的说法正确的是()

A.map的查询效率是O(log_2N),因为其底层使用的是二叉搜索树

B.map的key和value的类型可以相同

C.map中的有序只能是升序,不能是降序

D.map中的key可以直接修改

4. 下面关于map和set说法错误的是()

A.map中存储的是键值对,set中只储存了key

B.map和set查询的时间复杂度都是O(log_2N)

C.map和set都重载了[]运算符

D.map和set底层都是使用红黑树实现的


答案:

1. A

 A:正确,因为set要保证其有序,因此set中元素不能被直接修改,若要修改可以先删除,在插入

B:错误,map是C++98中已存在的,unordered_map是C++11中才有的

C:错误,map和set底层结构都是红黑树,而其底层红黑树在实现时并没有区分是存k模型还是KV 模型

D:错误,map中key是唯一的,每个key都有与之对应的value,经常需要通过key获取value,因此 map单重载了[ ]运算符, multimap中key是可以重复的,如果重载了[ ]运算符,给定 一个key时,就没有办法返回 value了,因此,multimap中没有重载[ ]运算符

2. B

  A:错误,set中可以存储键值对,实例化set时,将set中元素类型设置为pair即可

  B:正确,因为set中的key是不能重复的

  C:错误,set中任意类型元素都可以存储,存储对象时,需要用户提供比较规则

  D:错误,set默认是升序,正确,但是其内部默认不是按照大于比较,而是按照小于比较

3. B

A:错误,map的查询效率是O(log_2N)是正确的,但map的底层结构不是二叉搜索树,而是红黑树

B:正确,key和value的类型由用户自己设置,可以相同也可以不同,取决于应用场景需要

C:错误,map可以是升序,也可是降序,默认情况下是升序,如果需要降序,需要用户在实例化 map时指定比较规则

D:错误,map中key不能修改,因为如果修改了就不能保证红黑树的特性了,即有序

4. C

  A:正确,map和set的概念

  B:正确,因map和set的底层结构都是红黑树,而红黑树是近似的平衡二叉搜索树,故查询时间 复杂度为O(log_2N)

  C:错误,map中重载了[ ]运算符,因为其需要通过key获取value,set中没有

  D:正确


本篇完。

下一部分:AVL树的介绍和模拟实现,然后是红黑树。再就是set和map的模拟实现。​​​​​​​

穿越回来复习顺便贴个下篇链接:

从C语言到C++_27(AVL树)概念+插入接口实现(四种旋转)-CSDN博客

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

GR鲸鱼

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

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

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

打赏作者

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

抵扣说明:

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

余额充值