C++ set&&map

💓博主CSDN主页:麻辣韭菜💓

⏩专栏分类:C++知识分享

🚚代码仓库:C++高阶🚚

🌹关注我🫵带你学习更多C++知识
  🔝🔝



目录

前言 

 一.树形结构的关联式容器

(一)set

1.1 set介绍

 1.2 set模板参数

1.3 set成员函数

1.4 set使用 

 (二)multiset

1.1multiset介绍 

2.2 multiset模板参数 

 2.3 multiset常用成员函数 

2.4multiset使用 

 (三)map   

3.1 man介绍 

3.2 pair 

3.3 map常用函数 

 3.4 map使用

 (四) multimap

(五)set和map OJ题 

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

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


前言 

C++二叉搜索树 最后简单的讲解了搜索二叉树的应用场景,而本篇的set对应的就是K模型,

map对应KV模型。

 一.树形结构的关联式容器

(一)set

1.1 set介绍

set是C++标准模板库(STL)中的一个关联容器,它包含唯一元素的集合。以下是关于set的一些基本介绍:

  1. 唯一性:set中的元素都是唯一的,重复的元素在插入时会被自动忽略。

  2. 自动排序:set中的元素默认按照升序排序。如果需要自定义排序规则,可以通过提供比较函数或重载<运算符来实现。

  3. 迭代器:set支持前向迭代器,可以用来遍历容器中的元素。

  4. 常用操作:

  • insert():向set中插入一个元素。

  • find():查找一个元素是否存在于set中。

  • erase():删除一个元素。

  • size():返回set中元素的个数。

  • empty():检查set是否为空。

  • begin() 和 end():返回指向set中第一个元素和尾后位置的迭代器。

  1. 复杂度:set的插入、删除和查找操作的平均时间复杂度都是O(log n),其中n是set中元素的个数。

  2. 底层实现:set通常使用红黑树(一种自平衡的二叉搜索树)来实现,以确保元素的排序和快速查找。

 1.2 set模板参数

  • T: set中存放元素的类型,实际在底层存储<value, value>的键值对。
  • Compareset中元素默认按照小于来比较
  • Allocset中元素空间的管理方式,使用STL提供的空间配置器管理

1.3 set成员函数

  1. 构造函数:用于创建set对象。

  2. 析构函数:用于释放set对象占用的资源。

  3. begin():返回指向容器中第一个元素的迭代器。

  4. end():返回指向容器“尾部之后”的迭代器。

  5. rbegin():返回指向容器中最后一个元素的反向迭代器。

  6. rend():返回指向容器“起始之前”的反向迭代器。

  7. empty():检查容器是否为空。

  8. size():返回容器中元素的数量。

  9. max_size():返回容器可能包含的最大元素数量。

  10. clear():删除容器中的所有元素。

  11. insert(const value_type& val):在容器中插入一个元素。

  12. erase(const_iterator pos):删除迭代器pos指向的元素。

  13. erase(const key_type& key):删除键为key的元素。

  14. erase(const_iterator first, const_iterator last):删除范围[first, last)内的元素。

  15. find(const key_type& key) const:查找键为key的元素,若找到则返回指向该元素的迭代器,否则返回end()

  16. count(const key_type& key) const:返回键为key的元素在容器中出现的次数(对于set,这个值总是0或1,因为set中的元素是唯一的)。

  17. lower_bound(const key_type& key) 和 upper_bound(const key_type& key):返回指向不小于(大于)键key的第一个元素的迭代器。

  18. equal_range(const key_type& key):返回一个包含两个迭代器的pair,表示键为key的元素在容器中的范围。对于set,如果元素存在,这个范围只包含一个元素;如果不存在,这个范围是[end(), end())

1.4 set使用 

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


using namespace std;

void set_test()
{
	set<string> s;
	s.insert("张三");
	s.insert("李四");
	s.insert("王二麻子");
	s.insert("赵六");
	s.insert("孙七");
	set<string>::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	auto it1 = s.begin();
	while (it1 != s.end())
	{
		cout << *it1 << " ";
		++it1;
	}
	cout << endl;
}
void set_test2()
{
	//排序+去重
	set<int> s1;
	s1.insert(3);
	s1.insert(1);
	s1.insert(4);
	s1.insert(2);
	s1.insert(1);
	s1.insert(2);
	auto it1 = s1.begin();
	while (it1 != s1.end())
	{
		cout << *it1 << " ";
		++it1;
	}
	cout << endl;
}

int main()
{
	set_test();

	return 0;
}

 set 和vector list stack queue 这些容器使用方法到差不差 这里就不细讲了!!!

 (二)multiset

 

set前面加multi顾名思义那就是可以插入相同的值。 

1.1multiset介绍 

1. multiset是按照特定顺序存储元素的容器,其中元素是可以重复的。

2. multiset中,元素的value也会识别它(因为multiset中本身存储的就是<value, value>组成

的键值对,因此value本身就是keykey就是value,类型为T). multiset元素的值不能在容器

中进行修改(因为元素总是const),但可以从容器中插入或删除。

3. 在内部,multiset中的元素总是按照其内部比较规则(类型比较)所指示的特定严格弱排序准则进行排序。

4. multiset容器通过key访问单个元素的速度通常比unordered_multiset容器慢,但当使用迭

代器遍历时会得到一个有序序列。

5. multiset底层结构为二叉搜索树(红黑树)

5. multiset中的元素不能修改

6. multiset中找某个元素,时间复杂度为$O(log_2 N)$

7. multiset的作用:可以对元素进行排序

2.2 multiset模板参数 

 2.3 multiset常用成员函数 

 

multiset是C++ STL(标准模板库)中的一个容器,它允许存储重复的元素,并且元素在multiset中自动排序。下面是multiset的一些基本函数:

  1. 构造函数

    • multiset<T>(): 创建一个空的multiset
    • multiset<T>(const multiset& other): 创建一个multiset作为另一个multiset的副本。
  2. 插入元素

    • pair<iterator, bool> insert(const value_type& val): 插入一个元素。如果插入成功,返回指向新插入元素的迭代器;如果元素已存在,则不插入并返回指向已存在元素的迭代器。
    • void insert(const_iterator position, const value_type& val): 在指定位置前插入一个元素。注意,由于multiset是有序的,这个“位置”只是一个提示,实际插入位置可能根据元素的值进行调整。
    • void insert(const_iterator first, const_iterator last): 插入一个范围内的元素。
    • void insert(initializer_list<value_type> il): 使用初始化列表插入元素。
  3. 删除元素

    • size_type erase(const key_type& key): 删除所有等于指定键的元素,并返回删除的元素数量。
    • iterator erase(const_iterator position): 删除位于指定位置的元素,并返回指向下一个元素的迭代器。
    • iterator erase(const_iterator first, const_iterator last): 删除一个范围内的元素,并返回指向下一个元素的迭代器。
  4. 查找元素

    • iterator find(const key_type& key): 查找第一个等于指定键的元素,如果找到则返回指向该元素的迭代器,否则返回end()
    • size_type count(const key_type& key) const: 返回等于指定键的元素数量。
    • iterator lower_bound(const key_type& key): 返回指向第一个不小于指定键的元素的迭代器。
    • iterator upper_bound(const key_type& key): 返回指向第一个大于指定键的元素的迭代器。
    • pair<iterator, iterator> equal_range(const key_type& key): 返回一个范围,包含所有等于指定键的元素。
  5. 修改容器大小

    • void clear(): 删除multiset中的所有元素。
  6. 获取容器信息

    • bool empty() const: 如果multiset为空,则返回true
    • size_type size() const: 返回multiset中的元素数量。
    • iterator begin(): 返回指向第一个元素的迭代器。
    • const_iterator begin() const: 返回指向第一个元素的常量迭代器。
    • iterator end(): 返回指向multiset末尾之后位置的迭代器。
    • const_iterator end() const: 返回指向multiset末尾之后位置的常量迭代器。
    • reverse_iterator rbegin(): 返回指向最后一个元素的反向迭代器。
    • const_reverse_iterator rbegin() const: 返回指向最后一个元素的常量反向迭代器。
    • reverse_iterator rend(): 返回指向multiset开头之前位置的反向迭代器。
    • const_reverse_iterator rend() const: 返回指向multiset开头之前位置的常量反向迭代器。 这些函数可以让你有效地在multiset上进行各种操作。记住,由于multiset是有序的,因此插入和查找操作的复杂度通常是对数级别的。

2.4multiset使用 

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

using namespace std;

int main()
{
    // 1. 定义multiset,存储string类型
    multiset<string> ms;

    // 2. 插入元素
    ms.insert("apple");
    ms.insert("banana");
    ms.insert("apple");
    ms.insert("cherry");

    // 3. 访问元素
    for (auto it = ms.begin(); it != ms.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;

    // 4. 删除元素
    // 删除第一个出现的"apple"
    auto it = ms.find("apple");
    if (it != ms.end()) {
        ms.erase(it);
    }

    // 再次访问元素
    cout << "After deleting an 'apple': ";
    for (auto it = ms.begin(); it != ms.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;

    return 0;
}

 (三)map   

3.1 man介绍 

map是C++标准库中的一个关联容器,它存储的元素都是键值对(key-value pair),并且允许基于键快速访问各个元素。map中的元素总是按键值进行排序存储的。 以下是关于map的基本介绍:

1.存储结构:

  • map内部通常实现为一个平衡搜索树(比如红黑树),因此其元素的插入、删除和查找的时间复杂度都是对数级别的。

2.元素类型:

  • map中的元素是键值对(pair),其中键(key)是唯一的,用于标识元素,而值(value)是与该键相关联的数据。

3.键的唯一性:

  • map中,每个键只出现一次。如果试图插入具有相同键的新元素,该操作会替换原有的元素值。

4.排序:

  • map中的元素按键的升序自动排序。默认情况下,键的比较使用std::less<Key>,但也可以指定自定义的比较函数或对象。

5.基本操作:

  • 插入元素:使用insert成员函数或operator[](后者在键不存在时会创建一个新元素)。

  • 访问元素:使用operator[]at成员函数通过键来访问值。如果键不存在,operator[]会插入一个新元素并返回其引用,而at会抛出一个异常。

  • 删除元素:使用erase成员函数。

  • 查找元素:使用find成员函数来查找具有指定键的元素。

  • 遍历元素:可以使用迭代器来遍历map中的所有元素。

3.2 pair 

 

3.3 map常用函数 

插入元素

  • insert(const value_type& val): 插入一个元素(键值对)。

  • insert(const_iterator position, const value_type& val): 在指定位置前插入一个元素。

  • insert(InputIterator first, InputIterator last): 插入一个元素范围。

查找元素

  • find(const key_type& k): 查找键为k的元素,如果找到则返回指向该元素的迭代器,否则返回end()

  • count(const key_type& k): 查找键为k的元素的数量,因为map中的键是唯一的,所以结果要么是0(没找到)要么是1(找到了)。

删除元素

  • erase(const key_type& k): 删除键为k的元素。

  • erase(const_iterator position): 删除指定位置的元素。

  • erase(const_iterator first, const_iterator last): 删除一个元素范围。

获取元素数量

  • size(): 返回map中元素的数量。

判断map是否为空

  • empty(): 如果map为空则返回true,否则返回false。

访问元素

  • operator[] (const key_type& k): 通过键访问元素,如果键不存在则插入一个具有该键的新元素,并初始化为默认值。

  • at(const key_type& k): 通过键访问元素,如果键不存在则抛出std::out_of_range异常。

获取最大和最小元素

  • begin()end(): 分别返回指向map中第一个和最后一个元素的迭代器。

  • rbegin()rend(): 分别返回指向map中最后一个和第一个元素的反向迭代器(即从后往前遍历)。

修改键值

  • map中的键在插入后不能被修改,但是可以通过删除旧元素并插入新元素来“修改”键。值则可以通过迭代器或引用直接修改

 

 3.4 map使用

void map_test1()
{
	map<string, int> dict;
	dict.insert(make_pair("one", 1));
	dict.insert(make_pair("two", 2));
	dict.insert(make_pair("three", 3));
	dict.insert(make_pair("four", 4));
	//插入也可以用方括号
	dict["five"] = 5;
	dict["six"] = 6;
	dict["six"] = 6; //插入失败

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

}
void map_test2()
{
	string arr[] = { "西瓜", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉", "梨" };
	map<string, int> countMap;
	//传统写法插入
	for (auto& e : arr)
	{
		auto ret = countMap.find(e);
		if (ret == countMap.end())
		{
			countMap.insert(make_pair(e, 1));
		}
		else
		{
			ret->second++;
		}
	}
	for (auto &kv : countMap)
	{
		cout << kv.first << ": " << kv.second << endl;
	}
	// 【】写法
	/*for (auto& e : arr)
	{
		countMap[e]++;
	}

	for (auto& kv : countMap)
	{
		cout << kv.first << ":" << kv.second << endl;
	}*/
}

 (四) multimap

它和map区别就是可以插入重复键,但是他没有重载【】其他的用法都是一样。

 // 声明一个multimap变量
    multimap<string, int> mm;
    
    // 示例:向multimap中添加元素
    mm.insert(make_pair("apple", 1));
    mm.insert(make_pair("banana", 2));
    mm.insert(make_pair("apple", 3)); // 可以有重复的键
    
    // 示例:遍历multimap
    for (const auto& kv : mm) {
        cout << kv.first << ": " << kv.second << endl;
    }
    
    return 0;
}

(五)set和map OJ题 

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

 

class Solution {
public:
    struct Compare
    {
        bool operator()(const pair<string,int>& kv1, const pair<string,int>& kv2)
        {
            return kv1.second > kv2.second || (kv1.second == kv2.second && kv1.first < kv2.first);
        } 
        //次数最多的返回 或者次数相等相等的情况再根据字典序排序规则比较
    };
    vector<string> topKFrequent(vector<string>& words, int k) 
    {
        map<string,int> countMap;
        for(auto& kv:words)
        {
            countMap[kv]++; //插入+统计次数
        }
        vector<pair<string,int>> v(countMap.begin(),countMap.end()); //把数据方便vector这个容器 
        //为什么是vector 方便sort 关联式的容器 sort是排不了序的
        sort(v.begin(),v.end(),Compare());//sort排序不稳定 我们需要加仿函数自己控制排序
        vector<string> ret; //因为前面的v是键值对数据,我们再单独创建一个顺序表把first放到这个数组里再返回这个ret
        for(size_t i = 0; i<k; i++)
        {
            ret.push_back(v[i].first);
        }
        return ret;
    }
};

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

 

 

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
   // 先去重
        set<int> s1;
        for(auto e : nums1)
       {
            s1.insert(e);
       }
        set<int> s2;
        for(auto e : nums2)
       {
            s2.insert(e);
       }
        
        // set排过序,依次比较,小的一定不是交集,相等的是交集
        auto it1 = s1.begin();
        auto it2 = s2.begin();
        vector<int> ret;
        while(it1 != s1.end() && it2 != s2.end())
       {
            //为什么是小的++ 大的那个数,可能是小的那个set里面也有一个同样的
            //这时走大的不就错过了?
            if(*it1 < *it2)
           {
                it1++;
           }
            else if(*it2 < *it1)
           {
                it2++;
           }
            else
           {
                ret.push_back(*it1);
                it1++;
                it2++;
           }
       }
        return ret;
   }
};

map和set 底层实现逻辑还没有讲,下篇预告AVL树 对应就是map的底层原理,关注我带你学习更多C++知识!!!

  • 23
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值