set/multiset容器(含详细解释和例题)

一、set/multiset容器的简单介绍

        在 C++ 标准模板库(STL)中,set和 multiset是基于红黑树的关联容器,他能时刻保证序列中的数是有序的,用于存储唯一的元素集合,其中 set 的每个元素都必须是唯一的,而 multiset 允许有重复的元素,set中的元素默认按照升序进行排序,且不可更改排序方式,而multiset中的元素也默认按照升序排序,但可以通过自定义比较函数来改变排序方式。这类似于map和multimap的区别。

        使用set/multiset容器的头文件为 #include<set>

二、set/multiset容器相关函数介绍

1.构造一个空的容器,其中int代表容器中数据的类型。

set<int> s;

2.s.begin()/s.end():返回指向容器中第一个元素和末尾的迭代器。end() 指向最后一个元素之后的位置,用于标示容器的结束。下面代码为利用迭代器遍历集合中的元素(什么是迭代器已经在上个文章详细说明了,大家不了解的可以去看看哦)

 for(set<int>::iterator it = s.begin(); it != s.end(); ++it) {
        cout << *it << " ";
    }

另外大家需要注意的是s.end()指向的是容器中最后一个元素的下一个位置。

从 C++11 开始,你还可以使用更简洁的范围基 for 循环来遍历集合,这种方式不直接暴露迭代器,但内部仍然是通过迭代器来实现的:

    for (int num : s) {
        cout << num << " "; // 遍历元素
    }

3.s.rbegin()/ s.rend():返回指向容器中最后一个元素和开始前位置的逆向迭代器,用于逆序输出容器中的元素。

  for(auto it = s.rbegin(); it != s.rend(); ++it) {
        cout << *it << " ";
    }

4.s.empty():检查容器是否为空,如果容器为空返回 true,否则返回 false

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

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

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

8.插入函数:s.insert(elem) 将elem插入到容器当中,如果集合中已经存在一个等于 elem的元素,则插入操作不会改变集合(即,不会插入重复元素),并且 insert 方法也不会覆盖或删除已存在的元素。insert 方法返回一个 pair,其中包含一个迭代器和一个布尔值。迭代器指向已插入元素的位置,或者如果插入失败(因为元素已存在),则指向该已存在元素的位置。布尔值表示插入是否成功:true 表示新元素被插入,false 表示元素已存在。

auto result = s.insert(2);
if (result.second) {
    cout << "插入成功" << endl;
} else {
    cout << "插入失败" << endl;
}

9.删除元素:s.erase(elem)删除集合 s 中值为 elem 的元素。如果元素存在,它将被删除,不返回任何值,容器的大小减少;如果元素不存在,容器不会改变。

s.erase(pos)删除 position 迭代器指向的元素。

s.erase(first,late)删除[first, last) 范围内的所有元素。

// 删除指定位置的元素
auto it = s.find(4);
if (it != s.end()) {
    s.erase(it);
}

// 删除指定范围的元素
auto start = s.begin();
auto end = s.find(5);
s.erase(start, end); // 删除小于5的所有元素

10.s.count(elem)返回元素值为elem的个数。

11.s.find(elem)返回元素值为elem的第一个元素的位置,如果没有返回end()。

12.s.lower bound(val)/upper _bound(val):返回一个迭代器,指向第一个不小于(或大于)'val'的元素。

13.s.equal_range(val):equal_range(val) 返回的是一个 pair,其 first成员是一个迭代器,指向第一个不小于 val 的元素;second 成员是一个迭代器,指向第一个大于 val 的元素。对于 set 来说,如果 val 存在,则 firstsecond 之间的距离为 1,因为每个元素值唯一;如果 val 不存在,则 first == second,都指向 val 应该插入的位置。

三、用set容器解决问题

        某商场有 N 件商品,其中第i件的价格是 A i。现在该商场正在进行“买二赠一”的优惠活动,具体规则是:每购买 2 件商品,假设其中较便宜的价格是 P(如果两件商品价格一样,则 P 等于其中一件商品的价格),就可以从剩余商品中任选一件价格不超过的商品,免费获得这一件商品。可以通过反复购买2 件商品来获得多件免费商品,但是每件商品只能被购买或免费获得一次。
小明想知道如果要拿下所有商品(包含购买和免费获得),至少要花费多少钱?
输入格式:
        第一行包含一个整数 N。
        第二行包含  个整数,代表 A1,A2,A3,...,AN。
输出格式:
        输出一个整数,代表答案。

分析:由题意可知商品价格可以重复,所以采用multiset,我们可以先举个例子自己尝试,查找规律。

#include <iostream>
#include<set>
using namespace std;
long long int n, sum;
multiset<int> s;
int main() {
    cin >> n;
    for (int i = 0; i < n; i++) {
        int a; 
        cin >> a;
        s.insert(a);
    }//排序1 1 2 4 5 7 8 
    while (!s.empty()) {
        auto it = prev(s.end());//抵达最后一个元素 ,即最大的那个元素 
        int v1 =*it ; 
        sum += v1;
        if (it == s.begin()) break;//说明multiset中只剩下一个元素 
        int v2 = *prev(it); //第二个大的元素
        sum += v2;
        s.erase(prev(s.end()));
        s.erase(prev(s.end()));//删除7和8 
        auto lower = s.upper_bound(v2 / 2);//4
        s.erase(prev(lower));//删除2
        //序列中只剩下1 1 4 5
    }
    cout << sum;
    return 0;
}

  • 20
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值