【C++之set和multiset的基本应用】

C++之set和multiset的基本应用

前言:
前面篇章学习了C++对于二叉树搜索树的知识认识和了解,接下来继续学习,C++的set和multiset等知识。
/知识点汇总/
vecotr/list/deque…序列式容器:单纯的存储数据,存储的数据和数据之间没啥关联。
map/set… 关联式容器:不仅仅是是存储数据,一般还可以查找数据,存储的数据和数据之间存在一定的关联性

1、C++中set和multiset的简单介绍

在C++标准库中,set 和 multiset 是两种基于红黑树实现的关联容器,用于存储唯一(对于set)或可重复(对于multiset)的元素。这些元素在容器中始终按升序排列。

2、set的简单接口应用

set
set 是一个关联容器,它包含可以重复的键值对(在这里键和值相同)。set中的元素默认情况下总是按键的升序排序。set不允许两个元素具有相同的键。

特性:

唯一性:set中的元素是唯一的。
有序性:set中的元素默认按照升序排序。
插入/删除/查找效率高:由于set基于红黑树实现,其插入、删除和查找操作的时间复杂度通常为O(log n)。

#include <iostream>  
#include <set>  
int main() {  
    std::set<int> mySet;    
    // 插入元素  
    mySet.insert(10);  
    mySet.insert(20);  
    mySet.insert(30);   
    // 遍历set  
    for (const auto& elem : mySet) {  
        std::cout << elem << ' ';  
    }  
    std::cout << '\n';  
    // 查找元素  
    if (mySet.find(20) != mySet.end()) {  
        std::cout << "Found 20\n";  
    }   
    // 删除元素  
    mySet.erase(20);  
    return 0;  
}

3、multiset的简单接口应用

multiset
multiset 与 set 类似,但它允许存储重复的元素。这意味着你可以在 multiset 中插入多个相同的元素。

特性:

可重复性:multiset中的元素可以重复。
有序性:multiset中的元素默认按照升序排序。
插入/删除/查找效率高:同样基于红黑树实现,其插入、删除和查找操作的时间复杂度通常为O(log n)。

#include <iostream>  
#include <multiset>  
  
int main() {  
    std::multiset<int> myMultiSet;   
    // 插入元素,包括重复的元素  
    myMultiSet.insert(10);  
    myMultiSet.insert(20);  
    myMultiSet.insert(20);  
    myMultiSet.insert(30);    
    // 遍历multiset  
    for (const auto& elem : myMultiSet) {  
        std::cout << elem << ' ';  
    }  
    std::cout << '\n';   
    // 查找元素(因为可能存在多个相同的元素,所以可能需要遍历)  
    for (auto it = myMultiSet.find(20); it != myMultiSet.end() && *it == 20; ++it) {  
        std::cout << "Found 20\n";  
    }  
    // 删除元素(删除所有值为20的元素)  
    while (myMultiSet.find(20) != myMultiSet.end()) {  
        myMultiSet.erase(myMultiSet.find(20));  
    }  
    return 0;  
}

4、set和multiset的基本应用

4.1、set排序+去重

void test_set1()
{
	//排序+去重
	set<int> s1;
	s1.insert(1);
	s1.insert(12);
	s1.insert(3);
	s1.insert(1);
	s1.insert(6);
	s1.insert(2);

	set<int>::iterator it = s1.begin();
	while (it != s1.end())
	{
		//*it//不允许修改
		cout << *it << " ";
		++it;
	}
	cout << endl;

	vector<int> v = { 3,2,8,1,10,2 };
	set<int> s2(v.begin(), v.end());
	for (auto e : s2)
	{
		cout << e << " ";
	}
	cout << endl;

	cout << "-------------------" << endl;
	set<int> s3 = { 1,5,6,8,6,9,6,5,6 };
	//支持{}的初始化,因为有initializer_list的构造(C++11)
	for (auto e : s3)
	{
		cout << e << " ";
	}
	cout << endl;
	s3.erase(5);
	for (auto e : s3)
	{
		cout << e << " ";
	}
	cout << endl;

	s3.erase(s3.find(9));
	for (auto e : s3)
	{
		cout << e << " ";
	}
	cout << endl;

	auto pos = s3.find(6);
	if (pos != s3.end())
	{
		cout << *pos << endl;
		s3.erase(pos);
	}
	else
	{
		cout << "找不到" << endl;
	}
	for (auto e : s3)
	{
		cout << e << " ";
	}
	cout << endl;
}

4.2、找区间

void test_set2()
{
	set<int> myset;
	for (int i = 1; i < 10; i++)
	{
		myset.insert(i * 10);
	}
	for (auto e : myset)
	{
		cout << e << " ";
	}
	cout << endl;
	//找左闭右开区间的值
	//[30,60)
	auto itlow = myset.lower_bound(30);//>=x
	auto itup = myset.upper_bound(60);//>x
	//删除[30,60)范围的值
	myset.erase(itlow, itup);
	for (auto e : myset)
	{
		cout << e << " ";
	}
	cout << endl;
}

multiset
与set功能几乎类似
区别在于允许冗余。即:只排序不去重
multiset中,相等值可以在左边也可以在右边,具体看怎么实现。
因为是中序,默认是左边树开始,插入右边树;
所以find默认查找的是中序第一个节点
查找x,找到x后节点后,这个节点的左子树没有x节点,则它就是中序的第一个节点

void test_set3()
{
	multiset<int> s1;
	s1.insert(2);
	s1.insert(1);
	s1.insert(2);
	s1.insert(3);
	s1.insert(2);
	s1.insert(6);
	s1.insert(2);

	multiset<int>::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	auto pos = s1.find(2);
	while (pos != s1.end() && *pos == 2)
	{
		cout << *pos << " ";
		pos++;
	}
	cout << endl;
}

5、set巩固练习题

5.1、两个数组的交集

思路:1.arr的size相等就++ 2.不相等小的arr++

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

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

int main()
{
	vector<int> arr1 = { 1,6,8,3,5,9 };
	vector<int> arr2 = { 2,3,6,6,7,1 };
	Solution st;
	vector<int> arr3(arr1.size() + arr2.size());
	arr3 = st.inertsection(arr1, arr2);
	for (auto e : arr3)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

5.2、合并两个数组,去掉重复值

思路:利用set的性质,巧妙解决

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

class Solution
{
public:
	vector<int> Unionize(vector<int>& nums1, vector<int>& nums2)
	{
		set<int> s1(nums1.begin(), nums1.end());
		set<int> s2(nums2.begin(), nums2.end());
		size_t len1 = nums1.size();
		size_t len2 = nums2.size();
		vector<int> nums3;
		for (auto& e : s1)
		{
			nums3.push_back(e);
		}
		for (auto& e : s2)
		{
			nums3.push_back(e);
		}
		set<int> s3(nums3.begin(), nums3.end());
		vector<int> nums4;
		for (auto e : s3)
		{
			nums4.push_back(e);
		}
		return nums4;
	}
};

int main()
{
	vector<int> arr1 = { 1,6,8,3,5,9 };
	vector<int> arr2 = { 2,3,6,6,7,1 };
	Solution st;
	vector<int> arr3(arr1.size() + arr2.size());
	arr3 = st.Unionize(arr1, arr2);
	for (auto e : arr3)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

6、小结

set和multiset的区别

set和multiset在C++标准库中都是基于红黑树实现的关联容器,但它们之间存在一些关键的区别。

元素唯一性:

set:set中的元素是唯一的,即不能有两个元素具有相同的值。
multiset:multiset允许存储重复的元素,即可以有多个元素具有相同的值。

用途:

set:由于其元素的唯一性,set通常用于需要唯一集合的场合,例如存储不重复的标识符或关键字。
multiset:当需要记录元素出现的次数或存储可能重复的元素时,可以使用multiset。

操作:

由于两者都是基于红黑树的关联容器,所以它们的插入、删除和查找操作的时间复杂度都是O(log
n),其中n是容器中元素的数量。然而,由于multiset允许重复元素,因此在处理重复元素时可能需要进行额外的操作。

迭代:

当迭代set或multiset时,元素将按照升序排列。但需要注意的是,由于multiset允许重复元素,所以如果你迭代一个multiset并查找一个特定的值,可能会遇到多个相同的元素。

内存使用:

由于multiset需要额外的信息来跟踪重复元素的数量,因此它可能会比set使用更多的内存。然而,这种差异通常很小,并且通常不是选择这两个容器之间的主要决定因素。

修改元素:

需要注意的是,set和multiset都不直接支持修改容器中的元素值。这是因为它们是自动排序的容器,元素的位置取决于其值。如果你尝试修改一个元素的值,它可能会破坏容器的排序属性。如果你需要修改一个元素的值,通常的做法是先删除该元素,然后插入新的元素。

总的来说,set和multiset之间的主要区别在于它们是否允许重复的元素。根据你的需求(是否需要存储重复的元素),你可以选择使用set或multiset。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值