要 set 还是 map? 我全要

引子:

时隔多日,我又回来啦,接上回,我们讲到set的一小部分,我们今天来讲详细讲set与map,满满干货启动!根据应用场景的不同,STL总共实现了两种不同结构的管理式容器:树型结构与哈希结构。树型结构的关联式容器主要有四种:map、set、multimap、multiset。这四种容器的共同点是:使用平衡搜索树(即红黑树)作为其底层结果,容器中的元素是一个有序的序列。

扩展:序列的稳定性:在稳定的排序算法中,‌如果两个元素的值相等,‌它们在排序后的位置与排序前的相对顺序保持不变。‌例如,‌冒泡排序和插入排序是稳定的排序算法,‌而快速排序、‌选择排序和堆排序则是不稳定的。‌

pair的引入:

pair是C++ STL中定义的一个模板类,用于存储一对值,

用途pair常用于函数返回两个值的场景,或者作为键值对存储在某些容器中

pair对象支持比较操作符,如==, !=, <, >, <=, >=,这些操作符首先比较.first成员,如果相等,则比较.second成员

成员访问pair对象提供了访问其两个元素的方法,通常使用.first.second来分别访问第一个和第二个元素

对于set来说为pair<迭代器,bool>,对于map来说是pair<key,value>
set利用pair.second的:判断带环链表的入环点或是否带环等问题

map利用pair对应的second,可以做英文字典的查找,门禁卡等工作

什么是set?

总的来说有以下几点:

  1. 元素唯一性:set中的每个元素都是唯一的,不允许重复。如果尝试添加一个已经存在的元素,大多数情况下,这个操作会被忽略。

  2. 无序性:虽然你提到了"按照一定次序存储元素",但实际上大多数编程语言中的set并不保证元素的存储顺序。它们通常不按照元素的添加顺序或任何特定的顺序来存储元素。

  3. 元素作为键:在某些编程语言中,如C++的std::set,元素既是键也是值,因为set是基于键值对的集合,但键和值是相同的。

  4. 不可修改性:set中的元素通常是不可修改的,即一旦元素被添加到set中,就不能更改它的值。但是,你可以删除元素,然后重新插入一个新的元素。

  5. 基于红黑树的实现:在某些实现中,set可能使用红黑树来维护元素的有序性,这允许set在对数时间内进行查找、插入和删除操作。但是,并非所有set的实现都使用红黑树,有些可能使用哈希表。

  6. 类型为T:set可以存储任何类型的元素,只要这些元素支持比较操作,以便确定它们在set中的顺序(在基于红黑树的实现中)。

  7. 常量元素:在某些语言中,set中的元素被视为常量,意味着你不能更改它们,但可以添加或删除。

set的一些常用函数:

  1. empty():检查集合是否为空。

  2. size():返回集合中元素的数量。

  3. clear():移除集合中的所有元素。

  4. insert(value):向集合中插入一个新的元素。如果元素已存在,则不执行插入操作。

  5. erase(value):从集合中删除特定的元素。也可以删除指定范围内的元素。

  6. find(value):查找集合中是否存在特定值的元素,如果存在,返回指向该元素的迭代器;如果不存在,返回end()迭代器。

  7. count(value):返回集合中具有特定值的元素数量,对于set,这个函数总是返回0或1。

  8. lower_bound(value):返回指向大于或等于指定值的第一个元素的迭代器。

  9. upper_bound(value):返回指向大于指定值的第一个元素的迭代器。

  10. equal_range(value):返回一个范围,包含所有等于指定值的元素。对于set,这个范围由lower_boundupper_bound返回的迭代器界定。

  11. begin():返回指向集合开始的迭代器。

  12. end():返回指向集合结束(最后一个元素之后)的迭代器。

  13. rbegin():返回指向集合逆向开始的迭代器。

  14. rend():返回指向集合逆向结束的迭代器。

  15. swap(set):交换当前集合的内容与另一个集合的内容。

  16. key_comp():返回一个函数,该函数用于比较集合中的元素。

  17. value_comp():返回一个函数,该函数用于比较集合中元素的值。

什么是map?

1,map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元 素。

2. 在map中,键值key通常用于排序和唯一地标识元素,而值value中存储与此键值key关联的 内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型 value_type绑定在一起,为其取别名称为pair。

3,在内部,map中的元素总是按照键值key进行比较排序的。

4. map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序 对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。

5. map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。

6. map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。

map的重点--[ ]

[ ]总的来说:

情况一:[ ]如果已经有元素,则是find的功能,或修改,返回元素的迭代器, key不存在时抛异常

情况二:[ ]如果没有元素,则执行insert的一个功能,即插入加修改,返回插入元素的迭代器, key不存在时抛异常

总结 

1. map中的的元素是键值对 

2. map中的key是唯一的,并且不能修改

3. 默认按照小于的方式对key进行比较

4. map中的元素如果用迭代器去遍历,可以得到一个有序的序列

5. map的底层为平衡搜索树(红黑树),查找效率比较高O(log_2 N) 

6. 支持[]操作符,operator[]中实际进行插入查找

一个基础的实例:

map<string, string> high = { {"one","vector"}, {"two","List"} };
high.insert(make_pair("three", "queue"));
high["four"] = "stack";
for (const auto& e : high)
{
	cout << e.first << " ," << e.second << endl;
}

map常用函数:

  1. empty():检查map是否为空。

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

  3. clear():移除map中的所有元素。

  4. insert(value):向map中插入一个新的键值对。如果键已存在,则不会插入,并且可能返回一个指向现有元素的迭代器。

  5. erase(key):根据键删除元素。也可以删除指定范围内的元素或使用迭代器来删除元素。

  6. find(key):查找具有指定键的元素。如果找到,返回指向该元素的迭代器;如果未找到,返回end()迭代器。

  7. count(key):返回map中具有指定键的元素数量,对于map来说总是0或1。

  8. lower_bound(key):返回指向第一个不小于指定键的元素的迭代器。

  9. upper_bound(key):返回指向第一个大于指定键的元素的迭代器。

  10. equal_range(key):返回一个包含所有等于指定键的元素的区间,对于map来说,这个区间由lower_boundupper_bound返回的迭代器界定。

  11. begin():返回指向map开始的迭代器。

  12. end():返回指向map结束的迭代器。

  13. rbegin():返回指向map逆向开始的迭代器。

  14. **rend()``:返回指向map`逆向结束的迭代器。

  15. swap(map):交换当前map的内容与另一个map的内容。

  16. key_comp():返回一个函数,该函数用于比较map中的键。

  17. value_comp():返回一个函数,该函数用于比较map中的值(即键值对)。

  18. get_allocator():返回一个副本,该副本是用于map的分配器对象。

  19. max_size():返回map可以容纳的最大元素数量。

  20. operator[](key):通过下标访问或设置与指定键关联的值。如果键不存在,它将插入一个新元素,并使用默认构造函数构造值。

引用习题:

一,二个数组的交集

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

解题代码:

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
    set<int> number1(nums1.begin(),nums1.end());
    set<int> number2(nums2.begin(),nums2.end());
    
    auto it1=number1.begin();
    auto it2=number2.begin();
    vector<int> answer;
    while(it1!=number1.end()&it2!=number2.end())
    {
        if(*it1<*it2)
        {
          *it1++;
        }
        else if(*it1>*it2)
        {
            *it2++;
        }
        else
        {
            answer.push_back(*it1);
            *it1++;
            *it2++;
        }
    }
    return answer;
    }
};

二,前K个高频单词

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

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

解题代码:

class Solution {
public:
    // 仿函数
    struct compare {
        bool operator()(const pair<string, int>& h1,
                      const pair<string, int>& h2) {
            return h1.second>h2.second;
        }
    };

    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string, int> number;
        for (const auto& e : words) {
            number[e]++;
        }

        vector<pair<string, int>> temp(number.begin(), number.end());
        stable_sort(temp.begin(), temp.end(), compare());
        vector<string> answer;
        for (int i = 0; i < k; i++) {
            answer.push_back(temp[i].first);
        }

        return answer;
    }
};

感谢大家的收看,我们一起努力,争取高offer!,下一篇我将讲avl树啦

  • 28
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值