了解set

1. set的介绍

在这里插入图片描述

C++中的set是一种关联式容器,它能够存储同一数据类型的数据,并且能从一个数据集合中取出数据。在set中,每个元素的值都唯一,而且系统能根据元素的值自动进行排序 。set是用红黑树实现的,集合中的每个元素只出现一次,并且是排好序的(默认按键值升序排列),但可以通过自定义比较函数来改变排序方式 。
红黑树是一种自平衡的二叉搜索树,它可以保证插入、删除、查找等操作的时间复杂度为O(log n)。
set常用操作有:插入、删除、查找、遍历等。在C++ STL中,set容器定义在头文件中 。

2. set的使用

1. Member functions

在这里插入图片描述
constructor(构造):
在这里插入图片描述

函数声明功能介绍
set (const Compare& comp = Compare(), const Allocator& = Allocator() );构造空的set
set (InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& = Allocator() );用[first, last)区间中的元素构造set
set ( const set<Key,Compare,Allocator>& x);set的拷贝构造

destructor(析构):
~set():这将销毁所有容器元素,并释放设置容器使用其分配器
operator= copy (1) set& operator= (const set& x);

2.set的迭代器

在这里插入图片描述
迭代器是一种类似于指针的对象,它可以表示容器中元素的位置,并用于遍历容器中的元素,迭代器通常通过容器类提供的成员函数来获取,例如begin(), end(), rbegin(), rend()等。

函数声明功能介绍
begin返回set中起始位置元素的迭代器
end()返回set中最后一个元素后面的迭代器
rbegin()返回set第一个元素的反向迭代器,即end
rend()返回set最后一个元素下一个位置的反向迭代器,即rbegin
cbegin()返回set中起始位置元素的const迭代器
cend()返回set中最后一个元素后面的const迭代器
crbegin()返回set第一个元素的反向const迭代器,即cend
crend()返回set最后一个元素下一个位置的反向const迭代器,即crbegin
#include <iostream>
#include <set>
using namespace std;

int main()
{
	int a[] = { 3,5,2,4,1 };
	set<int> s1;//构造空的set
	set<int> s2(a, a + sizeof(a) / sizeof(a[0]));//用[first, last)区间中的元素构造set
	set<int> s3(s2);//set的拷贝构造

	//迭代器
	set<int>::iterator it1 = s2.begin();
	cout << "s2 :";
	while (it1 != s2.end())
	{
		cout << *it1 << ' ';
		++it1;
	}
	cout << endl;

	set<int>::reverse_iterator it2 = s3.rbegin();
	cout << "s3 :";
	while (it2 != s3.rend())
	{
		cout << *it2 << ' ';
		++it2;
	}
	cout << endl;
	return 0;
}

运行结果如下:
在这里插入图片描述

3. set的容量

在这里插入图片描述

函数声明功能介绍
empty检测set是否为空,空返回true,否则返回false
size返回set中有效元素的个数
max_size返回set容器可以容纳的元素的最大数量

int main()
{
	set<int> s = { 3,5,4,2,1 };
	cout << "s.empty:" << s.empty() << endl;
	cout << "s.size:" << s.size() << endl;
	cout << "s.max_size:" << s.max_size() << endl;

	return 0;
}

在这里插入图片描述

4.set修改操作

在这里插入图片描述

4.1 insert

在这里插入图片描述

在set中插入元素x,实际插入的是<x, x>构成的键值对,如果插入成功,返回<该元素在set中的位置,true>,如果插入失败,说明x在set中已经存在,返回<x在set中的位置,false>。pair包含两个成员变量,分别命名为first和second,它们分别存储了第一个和第二个元素的值。

int main()
{
	set<int> s = { 3,5,4,2,1 };
	auto p1 = s.insert(6);//插入成功
	auto p2 = s.insert(2);///插入失败
	cout << (*p1.first) << ":" << p1.second << endl;
	cout << (*p2.first) << ":" << p2.second << endl;

	return 0;
}

运行结果如下:
在这里插入图片描述

4.2 erase、swap和clear

函数声明功能介绍
erase删除set中的元素
swap交换set中的元素
clear将set中的元素清空

erase:
在这里插入图片描述

void erase ( iterator position ):删除set中position位置上的元素
size_type erase ( const key_type& x ):删除set中值为x的元素,返回删除的元素的个数
void erase ( iterator first, iterator last ):删除set中[first, last)区间中的元素

int main()
{
	set<int> s = { 3,5,4,2,1 };
	set<int>::iterator it = s.begin();
	++it; ++it; //it指向3的位置
	s.erase(it); //删除set中position位置上的元素
	it = s.begin();
	while (it != s.end())
	{
		cout << *it << ' ';
		++it;
	}
	cout << endl;

	s.insert(3);
	size_t e = s.erase(3); //删除set中值为x的元素,返回删除的元素的个数
	cout << "删除的个数:" << e << endl;

	s.insert(3);
	set<int>::iterator first = s.begin(); ++first;
	set<int>::iterator last = s.end(); --last;
	s.erase(first, last); //删除set中[first, last)区间中的[2,5)
	it = s.begin();
	while (it != s.end())
	{
		cout << *it << ' ';
		++it;
	}
	cout << endl;
	return 0;
}

运行结果如下:
在这里插入图片描述

swap和clear:

int main()
{
	set<int> s1 = { 3,5,4,2,1 };
	set<int> s2;
	s2.swap(s1);

	return 0;
}

调试结果如下:
在这里插入图片描述
在这里插入图片描述

4.3 emplace

std::set::emplace()函数是C++11中引入的一个新函数,它可以在不构造临时对象的情况下直接在set中构造元素。这个函数的用法和std::set::insert()函数类似,但是它可以避免不必要的构造和析构操作,从而提高程序的效率。具体来说,std::set::emplace()函数会在set中插入一个新元素,并返回一个指向这个元素的迭代器。如果这个元素已经存在于set中,则不会插入新元素,而是返回一个指向已有元素的迭代器。

struct Person
{
    string name;
    int age;
    Person(const string& n, int a) 
        : name(n)
        , age(a) 
    {}
    bool operator<(const Person& other) const 
    {
        return name < other.name;
    }
};
int main() 
{
    set<Person> people;
    people.emplace("Alice", 25);
    people.emplace("Bob", 30);
    people.emplace("Charlie", 20);
    for (const auto& person : people) 
    {
        cout << person.name << " is " << person.age << " years old.\n";
    }

    return 0;
}

上面的代码定义了一个名为Person的结构体,它包含一个字符串类型的name成员和一个整数类型的age成员。然后,我们定义了一个std::set类型的people变量,并使用std::set::emplace()函数向其中插入了三个Person对象。最后,我们遍历了people变量,并输出了每个Person对象的name和age成员。
在这里插入图片描述

5. observers(了解)

在这里插入图片描述
在C++中,std::set是一个关联容器,它包含一组经过排序的Key类型的唯一对象。key_comp函数返回一个比较对象,该对象可用于比较两个元素,以确定在容器1定义的严格弱排序中,第一个元素是否在第二个元素之前

int main()
{
    set<int> my_set = { 1, 2, 3, 4, 5 };
    auto comp = my_set.key_comp();
    for (auto it = my_set.begin(); it != my_set.end(); ++it)
    {
        cout << *it << " ";
        if (comp(*it, 3))
        {
            cout << "goes before 3\n";
        }
        else if (comp(3, *it))
        {
            cout << "goes after 3\n";
        }
        else
        {
            cout << "is equal to 3\n";
        }
    }
    return 0;
}

运行结果如下:
在这里插入图片描述
value_comp函数是std::set类的公共成员函数,它返回一个比较对象,该对象可用于比较两个元素,以确定它们在集合中的相对顺序。value_comp返回的比较对象是由std::set类的Compare模板参数构造的。默认情况下,此参数设置为std::less<Key>,这意味着元素按升序排列。如果要按降序排列元素,可以在定义集合时传递std::greater<Key>作为第二个模板参数。
以下是如何使用value_comp比较集合中两个元素的示例:

int main()
{
    set<int> mySet = { 1, 2, 3, 4, 5 };
    auto comp = mySet.value_comp();
    cout << "mySet contains:";
    for (auto it = mySet.begin(); it != mySet.end(); ++it)
    {
        cout << ' ' << *it;
    }
    cout << '\n';
    int highest = *mySet.rbegin();
    set<int>::iterator it = mySet.begin();
    do
    {
        cout << *it << " ";
    } while (comp(*(++it), highest));
    cout << '\n';
    return 0;
}

运行结果如下:
在这里插入图片描述
在本例中,我们首先创建一个名为mySet的集合,该集合包含从1到5的整数。然后,我们使用value_comp()函数创建一个名为comp的比较对象。我们使用这个比较对象来迭代集合中的元素,并按升序打印出来。

6.Operations(了解)

在这里插入图片描述
set中的find函数用于查找给定元素是否存在于set中。如果存在,则返回指向该元素的迭代器;否则,返回set::end() 。

set中的count函数用于返回set中等于给定值的元素的数量。 如果set中不存在该元素,则返回0 。

set中的lower_bound和upper_bound函数都是用于查找元素的函数。lower_bound函数返回一个迭代器,该迭代器指向第一个大于或等于给定值的元素。upper_bound函数返回一个迭代器,该迭代器指向第一个大于给定值的元素。 这两个函数都需要一个参数,即要查找的值。如果找到了该值,则返回指向该值的迭代器。如果没有找到该值,则返回指向下一个较大元素的迭代器。如果没有下一个较大元素,则返回set::end() 。

equal_range()函数返回一个迭代器对,表示与给定值相等的元素范围。第一个迭代器指向第一个等于给定值的元素,第二个迭代器指向最后一个等于给定值的元素的下一个位置。如果没有等于给定值的元素,则两个迭代器均指向第一个大于该值的元素。这个函数的时间复杂度为O(log(n))。

int main()
{
    //find
    cout << "find" << endl;
	set<int> s = { 3,5,1,4,2 };
	cout << *s.find(3) << endl; //返回指向该元素的迭代器
	set<int>::iterator it = s.find(6); //返回set::end()
	cout << (it == s.end()) << endl;
    cout << endl;

    //count
    cout << "count" << endl;
    if (s.count(3))
    {
        cout << "3 is present in the set" << endl;
    }
    else 
    {
        cout << "3 is not present in the set" << endl;
    }
    if (s.count(6)) 
    {
        cout << "6 is present in the set" << endl;
    }
    else 
    {
        cout << "6 is not present in the set" << endl;
    }
    cout << endl;

    //lower_bound upperr_bound
    cout << "lower_bound upperr_bound" << endl;
    set<int>::iterator l = s.lower_bound(2); //返回一个迭代器,该迭代器指向第一个大于或等于给定值的元素
    cout << *l << endl;
    l = s.upper_bound(2); //返回一个迭代器,该迭代器指向第一个大于给定值的元素
    cout << *l << endl;
    cout << endl;

    //equal_range
    cout << "equal_range" << endl;
    auto range = s.equal_range(3); //返回一个迭代器对,表示与给定值相等的元素范围
    for (auto it2 = range.first; it2 != range.second; ++it2)
    {
        cout << *it2 << " ";
    }
    cout << endl;

	return 0;
}

运行结果如下:
在这里插入图片描述

3.set有关的题目

在这里插入图片描述

两个数组的交集

首先可以直接用一个数组去遍历另一个数组,“完美” N^2的时间复杂度,这种方法直接舍去。

将数组中的元素输入到set中,可以得到有序而且不重复的数据,然后在找两个数列中的交集就非常简洁。(set的作用就是排序加去重)

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排过序,依次比较,小的一定不是交集,相等的是交集
        set<int>::iterator it1 = s1.begin();
        set<int>::iterator it2 = s2.begin();
        vector<int> ret;
        while(it1 != s1.end() && it2 != s2.end())
       {
       		//小的++
            if(*it1 < *it2)
           {
                it1++;
           }
            else if(*it2 < *it1)
           {
                it2++;
           }
            else
           {
                ret.push_back(*it1);
                it1++;
                it2++;
           }
       }
        return ret;
   }
};
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ly@눈_눈

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

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

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

打赏作者

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

抵扣说明:

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

余额充值