STL之set集合容器

2023-11-11

        set集合容器实现了红黑树(Red-Black Tree)的平衡二叉检索树的的数据结构,在插入元素时,它会自动调整二叉树的排列,把该元素放到适当的位置,以确保每个子树根节点的键值大于左子树所有节点的键值,而小于右子树所有节点的键值;另外,还得确保根节点的左子树的高度与有字数的高度相等,这样,二叉树的高度最小,从而检索速度最快。要注意的是,它不会重复插入相同键值的元素,而采取忽略处理。

        平衡二叉检索树的检索使用中序遍历算法,检索效率高于vector、deque、和list的容器。另外,采用中序遍历算法可将键值由小到大遍历出来,所以,可以理解为平衡二叉检索树在插入元素时,就会自动将元素按键值从小到大的顺序排列。

        构造set集合的主要目的是为了快速检索,使用set前,需要在程序头文件中包含声明“#include<set>”。

1.创建set集合对象

           创建set对象时,需要指定元素的类型,这一点和其他容器一样。

#include<iostream>
#include<set>
using namespace std;
int main()
{
	set<int> s;
	return 0;
}
2.元素的插入与中序遍历

        采用inset()方法把元素插入到集合中,插入规则在默认的比较规则下,是按元素值从小到大插入,如果自己指定了比较规则函数,则按自定义比较规则函数插入。使用前向迭代器对集合中序遍历,结果正好是元素排序后的结果。

#include<iostream>
#include<set>
using namespace std;
int main()
{
	set<int> s;
	s.insert(5); //第一次插入5,可以插入
	s.insert(1);
	s.insert(6);
	s.insert(3);
	s.insert(5); //第二次插入5,重复元素,不会插入
	set<int>::iterator it; //定义前向迭代器
	//中序遍历集合中的所有元素
	for(it = s.begin(); it != s.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
	return 0;
}
//运行结果:1 3 5 6
3.元素的方向遍历

        使用反向迭代器reverse_iterator可以反向遍历集合,输出的结果正好是集合元素的反向排序结果。它需要用到rbegin()和rend()两个方法,它们分别给出了反向遍历的开始位置和结束位置。

#include<iostream>
#include<set>
using namespace std;
int main()
{
	set<int> s;
	s.insert(5); //第一次插入5,可以插入
	s.insert(1);
	s.insert(6);
	s.insert(3);
	s.insert(5); //第二次插入5,重复元素,不会插入
	set<int>::reverse_iterator rit; //定义反向迭代器
	//反向遍历集合中的所有元素
	for(rit = s.rbegin(); rit != s.rend(); rit++)
	{
		cout << *rit << " ";
	}
	cout << endl;
	return 0;
}
//运行结果:6 5 3 1
4.元素的删除

        与插入元素的处理一样,集合具有高效的删除处理功能,并自动重新调整内部的红黑树的平衡。删除的对象可以是某个迭代器位置上的元素、等于某键值的元素、一个区间上的元素和清空集合。

#include<iostream>
#include<set>
using namespace std;
int main()
{
	set<int> s;
	s.insert(5); //第一次插入5,可以插入
	s.insert(1);
	s.insert(6);
	s.insert(3);
	s.insert(5); //第二次插入5,重复元素,不会插入
	s.erase(6); //删除键值为6的元素
	set<int>::reverse_iterator rit; //定义反向迭代器
	//反向遍历集合中的所有元素
	for(rit = s.rbegin(); rit != s.rend(); rit++)
	{
		cout << *rit << " ";
	}
	cout << endl;	
	set<int>::iterator it;

	it = s.begin();
	for(int i = 0; i < 2; i++)
		it = s.erase(it); 
	for(it = s.begin(); it != s.end(); it++)
		cout << *it << " ";
	cout << endl;

	s.clear();
	cout << s.size() << endl;

	return 0;
}
/*
运行结果:
5 3 1
5
0    
*/
5.元素的检索

          使用find()方法对集合进行检索,如果找到查找的的键值,则返回该键值的迭代器位置;否则,返回集合最后一个元素后面的一个位置,即end()。

#include<iostream>
#include<set>
using namespace std;
int main()
{
	set<int> s;
	s.insert(5); //第一次插入5,可以插入
	s.insert(1);
	s.insert(6);
	s.insert(3);
	s.insert(5); //第二次插入5,重复元素,不会插入
	set<int>::iterator it;
	it = s.find(6); //查找键值为6的元素
	if(it != s.end())
		cout << *it << endl;
	else
		cout << "not find it" << endl;
	it = s.find(20);
	if(it != s.end())
		cout << *it << endl;
	else
		cout << "not find it" << endl;
	return 0;
}
/*
运行结果:
6
not find it   
*/

下面这种方法也能判断一个数是否在集合中:

#include <cstdio>
#include <set>
using namespace std;
int main() {
    set <int> s;
    int a;
    for(int i = 0; i < 10; i++)
        s.insert(i);
    for(int i = 0; i < 5; i++) {
        scanf("%d", &a);
        if(!s.count(a)) //不存在
            printf("does not exist\n");
        else
            printf("exist\n");
    }
    return 0;
}


6.自定义比较函数

         使用insert将元素插入到集合中去的时候,集合会根据设定的比较函数奖该元素放到该放的节点上去。在定义集合的时候,如果没有指定比较函数,那么采用默认的比较函数,即按键值从小到大的顺序插入元素。但在很多情况下,需要自己编写比较函数。

编写比较函数有两种方法。

(1)如果元素不是结构体,那么可以编写比较函数。下面的程序比较规则为按键值从大到小的顺序插入到集合中。

#include<iostream>
#include<set>
using namespace std;
struct mycomp
{ //自定义比较函数,重载“()”操作符
	bool operator() (const int &a, const int &b)
	{
		if(a != b)
			return a > b;
		else
			return a > b;
	}
};
int main()
{
	set<int, mycomp> s; //采用比较函数mycomp
	s.insert(5); //第一次插入5,可以插入
	s.insert(1);
	s.insert(6);
	s.insert(3);
	s.insert(5); //第二次插入5,重复元素,不会插入
	set<int,mycomp>::iterator it;
	for(it = s.begin(); it != s.end(); it++)
		cout << *it << " ";
	cout << endl;
	return 0;
}
/*
运行结果:6 5 3 1  
*/
(2)如果元素是结构体,那么可以直接把比较函数写在结构体内。

#include<iostream>
#include<set>
#include<string>
using namespace std;
struct Info
{
	string name;
	double score;
	bool operator < (const Info &a) const // 重载“<”操作符,自定义排序规则
	{
		//按score由大到小排序。如果要由小到大排序,使用“>”即可。
		return a.score < score;
	}
};
int main()
{
	set<Info> s;
	Info info;

	//插入三个元素
	info.name = "Jack";
	info.score = 80;
	s.insert(info);
	info.name = "Tom";
	info.score = 99;
	s.insert(info);
	info.name = "Steaven";
	info.score = 60;
	s.insert(info);

	set<Info>::iterator it;
	for(it = s.begin(); it != s.end(); it++)
		cout << (*it).name << " : " << (*it).score << endl; 
	return 0;
}
/*
运行结果:
Tom : 99
Jack : 80
Steaven : 60
*/





本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STL之set集合容器 的相关文章

随机推荐

  • Win11家庭版完美解决旧版exe的DPI显示高清修复

    由于Win11家庭版的一些限制 不能直接按Win R搜索打开gpedit msc来执行相关操作 修改注册表对普通用户又太危险 因此本文介绍了一种更简便的操作方法 来设置旧程序对现在电脑的高DPI的适配 一共12个步骤 步骤1 打开 开始 搜
  • flutter 超详细的sqflite数据库使用详解

    前言 数据持久化存储是app开发过程中比较常见的需求 对于简单的配置数据我们可以通过SharedPreference来实现 但是如果是类似用户列表 商品列表等的大量复杂数据 再使用SharedPreference来存储就不合适了 本篇我们就
  • curl命令多行执行

    window环境执行 分割符是 curl http surge jdfmgt com core r coreAutoInitiateMain testAddData X POST d objectCreateCount 1 typeCode
  • leecode151 反转字符串中的单词(附有手写思路)

    丑陋的思路 StringJoiner版本 前言 刚开始我是用StringJoiner写的 因为我看到这个每个元素之间有一个固定的空格我就想着能够直接用这个StringJoiner来进行书写 但是我提交的时候说这个StringJoiner无法
  • leetcode分类刷题:哈希表(Hash Table)(三、循环存在问题)

    1 当需要快速判断某元素是否出现在序列中时 就要用到哈希表了 2 本文针对的总结题型为给定的序列或需要构造的序列中是否存在循环 与 160 相交链表 141 环形链表 142 环形链表 II的题型一样 202 快乐数 这道题还考察如何对正整
  • AndroidStudio内各个模拟器的安装位置

    As中 下载的本地模拟器的位置位于 android avd目录下 当该目录被删除后 打开AndroidStudio的AVD 会发现所有的下载过的模拟器都没有了
  • 【2021-04-07华为机试】第二题:各任务执行完毕需要的时间

    题目 给定N个任务 1 lt N lt 100 任务编号从0开始顺序累加 这N个任务在系统中排队顺序执行 每个任务的自身执行时间为非负整数 依次为t1 t2 tn 部分任务之间存在依赖关系的 某任务所依赖的任务如果没有执行 则该任务需要重回
  • IDEA 中设置自动补全方法

    最近转用 IDEA 但习惯于 Eclipse 的快捷键和快捷输入 以下是在 IDEA 中增添快捷键和快捷输入的方法 1 File Settings 2 Editor Live Templates Add Template Group gt
  • Ant Design Pro新增页面步骤

    新增页面步骤 根据页面结构规范创建页面文件后 接着在项目根目录寻找config文件夹下的routes js中添加该页面项的路由配置 如创建子路由则在父路由下定义routes属性 值为一个数组 数组中为该路由的子路由路由配置项 如下图 exp
  • 微信隐藏功能系列3:微信关闭朋友圈广告推送

    我们使用微信好多年了 这个工具不仅仅在社交上为我们带来许多好处 工作 消费中也是给我们带来不少方便之处 大家对微信隐藏功能了解多少 本期分享 微信关闭朋友圈广告推送 虽然微信为我们带来许多方便 但令人不适的东西也是有的 广告就是其中之一 特
  • python如何创建二维数组

    关于python中的二维数组 主要有list和numpy array两种 好吧 其实还有matrices 但它必须是2维的 而numpy arrays ndarrays 可以是多维的 两者可以相互转化 下边是两者区别 数组list gt g
  • linux va_start 编译,如何把unix 下的c程序移植到suse linux下,编译出错?

    FILE gfp out stdout 第45行 报 err c 45 error initializer element is not constant include int err set info char ps error typ
  • c++:STL容器及其接口(string、vector、deque、stack、queue、list、set/multiset、map/multimap)

    STL Standard Template Library 标准模板库 目录 一 STL 六大组件简介 二 string容器 2 1 string容器基本概念 2 2 string 构造函数 2 3 string基本赋值操作 2 4 str
  • 第五章可视化

    1散点图 1 代码 A 未处理异常值 import ggplot as gp import pandas as pd import numpy as np crime pd read csv crimeRatesByState2005 cs
  • git交互式暂存 git add -i 这个骚操作存在的意义为何

    文章目录 启用交互暂存 暂存常用的命令 交互暂存的意义在哪 应该场景的进一步说明 你已经能非常熟练的使用 git了 暂存是其中最基本的操作了 交互暂存是暂存的高级用法 虽然可以不用 但是在某些特定场景下 可以提高我们的工作效率 下边请看详细
  • Opencv3.1+python2.7的CentOS7安装

    time Jan 13 2016 20 29 author duanxxnj 163 com 花了两天时间才把Openv3 1的Python安装完成 中间遇到了好多奇怪的错误 在这里记录下整个安装过程 系统环境 Duanxx CentOS
  • js debugger的两种方式

    第一种 在js代码中加上debugger class ReactiveEffect constructor fn scheduler this fn fn this scheduler scheduler this active true
  • HDU - 6126 Give out candies

    Give out candies 题解 第一次遇见这样处理的网络流模型 将问题转换成最小割问题 具体的题解参考自 传送门 先将每个人的拆成m个人 然后s向第1人连边流量为inf 第i个人向第i 1个人连边 流量为 3000 w 将t视为每组
  • 自用IdeaVim配置

    具体配置如下 nnoremap
  • STL之set集合容器

    set集合容器实现了红黑树 Red Black Tree 的平衡二叉检索树的的数据结构 在插入元素时 它会自动调整二叉树的排列 把该元素放到适当的位置 以确保每个子树根节点的键值大于左子树所有节点的键值 而小于右子树所有节点的键值 另外 还