STL算法之set相关算法

news2025/2/12 3:54:56

        STL一共提供了四种与set(集合)相关的算法,分别是并集(union)、交集(intersection)、差集(difference)、对称差集(symmetric difference)。

目录

set_union

set_itersection

set_difference

set_symmetric_difference


        所谓set,可细分为数学上定义的和STL的定义两种,数学上的set允许元素重复而未经排序,例如{1,1,4,6,3},STL的定义(也就是set容器)则要求元素不得重复,并且经过排序,例如{1,3,4,6}。本节的四个算法所接受的set,必须是有序区间(sorted range),元素值可重复出现。换句话说,它们可接受STL的set/multiset容器作为输入区间。

        SGI另外提供了hash_set/hash_multiset两种容器,以hashtable为底层机制。其内的元素并未呈现排序状态,所以虽然名称也是set字样,缺不可以应用于本节的四个算法。

        本节四个算法都至少有四个参数,分别表现两个set区间,以下所有说明都以S1代表第一区间[first1, last1),以S2代表第二区间[first2, last2).每一个set算法都提供两个版本,第二个版本允许用户指定"a<b"的意义,因为这些算法判断两个元素是否相等的依据,完全靠“小于”运算。

        a <b && b< a 推导出 a==b

        以下程序测试四个set相关算法。欲使用它们,必须包含<algorithm>

#include <set>
#include <iostream>
#include <algorithm>
#include <iterator>
using namespace std;

template <class T>
struct display {
    void operator() (const T& x) {
        cout << x << " ";
    }
};

int main() {
    int ia1[6] = {1, 3, 5, 7, 9, 11};
    int ia2[7] = {1, 1, 2, 3, 5, 8, 13};

    multiset<int> S1(ia1, ia1+6);
    multiset<int> S2(ia2, ia2+7);

    for_each(S1.begin(), S1.end(), display<int>());// 1 3 5 7 9 11
    cout << endl;
    for_each(S2.begin(), S2.end(), display<int>());// 1 1 2 3 5 8 13
    cout << endl;

    auto first1 = S1.begin();
    auto last1 = S1.end();
    auto first2 = S2.begin();
    auto last2 = S2.end();
    cout <<  "Union of S1 and S2:";
    set_union(first1, last1, first2, last2, ostream_iterator<int>(cout, " ")); // 1 1 2 3 5 7 9 11 13
    cout << endl;

    first1 = S1.begin();
    first2 = S2.begin();
    cout << "intersection of S1 and S2:";
    set_intersection(first1, last1, first2, last2, ostream_iterator<int>(cout, " "));// 1 3 5
    cout << endl;

    first1 = S1.begin();
    first2 = S2.begin();
    cout << "difference of S1 and S2 (S1-S2): " ;
    set_difference(first1, last1, first2, last2, ostream_iterator<int>(cout, " ")); // 7 9 11
    cout << endl;

    first1 = S1.begin();
    first2 = S2.begin();
    cout << "Symmetric difference of S1 and S2: " ;
    set_symmetric_difference(first1, last1, first2, last2, ostream_iterator<int>(cout, " ")); // 1 2 7 8 9 11 13
    cout << endl;

    first1 = S1.begin();
    first2 = S2.begin();
    cout << "difference of S2 and S1 (S2-S1): ";
    set_difference(first2, last2, first1, last1, ostream_iterator<int>(cout, " ")); // 1 2 8 13
    cout << endl;
    return 0;
}

        执行结果如下:

1 3 5 7 9 11 
1 1 2 3 5 8 13 
Union of S1 and S2:1 1 2 3 5 7 8 9 11 13 
intersection of S1 and S2:1 3 5 
difference of S1 and S2 (S1-S2): 7 9 11 
Symmetric difference of S1 and S2: 1 2 7 8 9 11 13 
difference of S2 and S1 (S2-S1): 1 2 8 13 

        请注意,当集合(set)允许重复元素的存在时,并集、交集、差集、对称差集的定义,都与直观定义有些微的不同。例如上述的并集结果,我们会直观以为是{1,2,3,5,7,8,9,11,13},而上述的对称差结果,我们会直观以为是{2,7,8,9,11,13},这都是未考虑重复元素的结果。以下各小节会详细说明。

set_union

        算法set_union可构造S1、S2之并集。也就是说,它能构造出集合S1\cup S2,此集合内含S1或S2内的每一个元素。S1、S2及其并集都是以排序区间表示。返回值为一个迭代器,指向输出区间的尾端。

        由于S1和S2内的每一个元素都不需要唯一,因此,如果某个值在S1出现n次,在S2出现m次,那么该值在输出区间会出现max(n,m)次,其中n个来自S1,其余来自S2,在STL set容器内,m\leq 1n\leq 1

        set_union是一种稳定(stable)操作,意思是输入区间内的每个元素的相对顺序都不会改变。set_union有两个版本,差别在于如何定义某个元素小于另一个元素。第一版本使用operator<进行比较,第二版本采用仿函数comp进行比较。

template <class InputIterator1, class InputIterator2, class OutputIterator>
OutputIterator set_union(InputIterator1 first1, InputIterator1 last1,
                         InputIterator2 first2, InputIterator2 last2,
                         OutputIterator result) {
    while (first1 != last1 && first2 != last2) {
        if (*first1 < *first2) {
            *result = *first1;
            ++first1;
        } else if (*first2 < *first1) {
            *result = *first2;
            ++first2;
        } else {
            *result = *first1;
            ++first1;
            ++first2;
        }
        ++result;
    }
    // 此时[first1,last1)和[first2,last2)至少有一个空白区间,边界剩下的是都属于union的元素
    return copy(first2, last2, copy(first1, last1, result));
}

        从以上合并的过程,可以看出主要是利用了set/multi_set经过排序的特性,而后对并集的特例化处理。和数学定义上的union处理略有差异。

set_itersection

        算法set_itersection可构造S1,S2之交集。也就是说,它能构造出集合S1\cap S2,此集合内含同时出现在S1和S2的每一个元素。S1、S2及其交集都是以排序区间表示。返回值为一个迭代器,指向输出区间的尾端。

        由于S1和S2内的每个元素都不需要唯一,因此,如果某个值在S1出现n次,在S2出现m次,那么该值在输出区间出现min(n,m)次,并且全部来自S1.在STL set内,m\leq 1n\leq 1

        set_itersection是一种稳定(stable)的操作,意思是输出区间内的每个元素的相对顺序都和S1内的相对顺序相同。它有两个版本,其差异同set_union.其代码定义如下:

template <class InputIterator1, class InputIterator2, class OutputIterator>
OutputIterator set_itersection(InputIterator1 first1, InputIterator1 last1,
                         InputIterator2 first2, InputIterator2 last2,
                         OutputIterator result) {
    while (first1 != last1 && first2 != last2) {
        if (*first1 < *first2) {
            ++first1;
        } else if (*first2 < *first1) {
            ++first2;
        } else { // *first1 == *first2
            *result = *first1;
            ++first1;
            ++first2;
        }
        ++result;
    }
    return result;
}

        对照set_itersection和set_union的算法实现,可发现内部迭代器的前进逻辑是一致的;只是输出时,只讲*first1==*first2的数据输出到result。对于边界情况,因为其中一组迭代器已经为空,所以也就没有了新的元素加入,直接返回了result;

set_difference

        算法set_difference可构造S1、S2只差集。也就是说,它能构造集合S1-S2,此集合内容"出现于S1但不出现于S2"的每一个元素。S1、S2及其交集都是以排序区间表示。返回值为一个迭代器,指向输出区间的尾端。

        由于S1和S2内的每个元素都不需要唯一,因此,如果某个值在S1出现n次,在S2出现m次,那么该值在输出区间出现max(n-m,0)次

        set_difference是一种稳定操作,输出相对顺序保持S1内的相对顺序。代码如下:

template <class InputIterator1, class InputIterator2, class OutputIterator>
OutputIterator set_difference(InputIterator1 first1, InputIterator1 last1,
                         InputIterator2 first2, InputIterator2 last2,
                         OutputIterator result) {
    while (first1 != last1 && first2 != last2) {
        if (*first1 < *first2) {
            *result = *first1;
            ++first1;
            ++result;
        } else if (*first2 < *first1) {
            ++first2;
        } else {
            ++first1;
            ++first2;
        }
    }
    return  copy(first1, last1, result);
}

        有了前面set_union及set_itersecion算法的经验,可看出迭代器的逻辑还是保留的相同的步伐。只是输出给result的值,只保留了*first1 < *first2的部分;正好符合S1-S2的特性。

set_symmetric_difference

        算法set_symmetric_difference可构造S1、S2之对称差集。也就是构造出(S1-S2)\cup (S2-S1),此集合内含"出现在S1但不出现于S2"以及“出现在S2不出现在S1”的每一个元素。

        有了前三个算法的基础,很容易得出set_symmetric_difference的结果包含*first1<*first2,以及*first2-*first1的结果,同时需要将边界情况保留。其代码如下:

template <class InputIterator1, class InputIterator2, class OutputIterator>
OutputIterator set_symmetric_difference(InputIterator1 first1, InputIterator1 last1,
                         InputIterator2 first2, InputIterator2 last2,
                         OutputIterator result) {
    while (first1 != last1 && first2 != last2) {
        if (*first1 < *first2) {
            *result = *first1;
            ++first1;
            ++result;
        } else if (*first2 < *first1) {
            *result = *first2
            ++first2;
            ++result;
        } else {
            ++first1;
            ++first2;
        }
    }
    return  copy(first2, last2, copy(first1, last1, result));
}

 

参考文档《STL源码剖析》---侯捷

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2251014.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

鸿蒙ArkUI-X已更新适配API13啦

ArkUI-X 5.0.1 Release版配套OpenHarmony 5.0.1 Rlease&#xff0c;API 13&#xff0c;新增适配部分API 13接口支持跨平台&#xff1b;框架能力进一步完善&#xff0c;支持Android应用非压缩模式&#xff0c;支持Android Fragment对接跨平台。ACE Tools工具易用性提升&#xff…

rest-assured multiPart上传中文名称文件,文件名乱码

rest-assured是一个基于java语言的REST API测试框架&#xff0c;在使用rest-assured的multipart 上传文件后&#xff0c;后端获取的文件名称乱码。截图如下&#xff1a; 原因是rest-assured multipart/form-data默认的编码格式是US-ASCII&#xff0c;需要设置为UTF-8。 Befo…

前端页面或弹窗在线预览文件的N种方式

需求&#xff1a;后端返回给前端一个地址后&#xff0c;在前端页面上或则在弹框中显示在线的文档、表格、图片、pdf、video等等&#xff0c;嵌入到前端页面 方式一&#xff1a; 使用vue-office 地址&#xff1a;vue-office简介 | vue-office 个人感觉这个插件是最好用的&#x…

<<WTF-Solidity>>学习笔记(part 21-24)

part 21: 调用已部署合约 在Solidity中&#xff0c;一个合约可以调用另一个合约的函数&#xff0c;这在构建复杂的DApps时非常有用。本教程将会介绍如何在已知合约代码&#xff08;或接口&#xff09;和地址的情况下&#xff0c;调用已部署的合约。 part 22: Call call 是…

element的el-table表格标题用css自定义是否必填,用添加伪类的方式标红色*

element的el-table表格标题用css自定义是否必填添加伪类红色 * 效果图如下&#x1f447; el-table组件的html部分 css部分 /deep/.el-table__header-wrapper{.el-table__header{.has-gutter tr .el-table__cell:nth-of-type(3) .cell:before{content: *;color:red}.has-gutte…

2024 ccpc 辽宁省赛 E(构造 思维?)L(二分+一点点数论知识?)

E 题意&#xff1a; 可以注意到&#xff1a; 我的两种方格都四个方格的大小。 所以 如果存在一种摆放方式 那么 4|nm。 再考虑一种特殊的情况 22 &#xff0c;此时虽然我的积是4 但是无法摆放的。 1>对于 4 | n,或者 4 | m.我直接摆放第二种方格就可以了。 如果我n 是4 的…

【python】OpenCV—Tracking(10.5)—dlib

文章目录 1、功能描述2、代码实现3、效果展示4、完整代码5、涉及到的库函数dlib.correlation_tracker() 6、参考 1、功能描述 基于 dlib 库&#xff0c;实现指定类别的目标检测和单目标跟踪 2、代码实现 caffe 模型 https://github.com/MediosZ/MobileNet-SSD/tree/master/…

Ps:存储 Adobe PDF

在 Adobe Photoshop 中&#xff0c;将图像保存为 PDF 文件时&#xff0c; 会弹出“存储 Adobe PDF” Save Adobe PDF对话框。在此对话框中提供了多个选项&#xff0c;用于控制 PDF 文件的输出&#xff0c;包括一般设置&#xff08;选择预设、兼容性和保留编辑功能&#xff09;、…

【查询目录】.NET开源 ORM 框架 SqlSugar 系列

.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列【数据事务…

论文笔记(五十七)Diffusion Model Predictive Control

Diffusion Model Predictive Control 文章概括摘要1. Introduction2. Related work3. 方法3.1 模型预测控制3.2. 模型学习3.3. 规划&#xff08;Planning&#xff09;3.4. 适应 4. 实验&#xff08;Experiments&#xff09;4.1. 对于固定奖励&#xff0c;D-MPC 可与其他离线 RL…

hadoop环境配置-创建hadoop用户+更新apt+安装SSH+配置Java环境

一、创建hadoop用户(在vm安装的ubantu上打开控制台) 1、sudo useradd -m hadoop -s /bin/bash &#xff08;创建hadoop用户&#xff09; 2、sudo passwd hadoop (设置密码) 3、sudo adduser hadoop sudo&#xff08;将新建的hadoop用户设置为管理员&#xff09; 执行如下图 将…

基于 SpringBoot 的新冠密接者跟踪系统:如何实现高效信息推送功能

第2章 程序开发技术 2.1 Mysql数据库 为了更容易理解Mysql数据库&#xff0c;接下来就对其具备的主要特征进行描述。 &#xff08;1&#xff09;首选Mysql数据库也是为了节省开发资金&#xff0c;因为网络上对Mysql的源码都已进行了公开展示&#xff0c;开发者根据程序开发需要…

Python 自动化办公的 10 大脚本

大家好&#xff0c;我是你们的 Python 讲师&#xff01;今天我们将讨论 10 个实用的 Python 自动化办公脚本。这些脚本可以帮助你简化日常工作&#xff0c;提高效率。无论是处理 Excel 文件、发送邮件&#xff0c;还是自动化网页操作&#xff0c;Python 都能派上用场。 1. 批量…

Android 使用OpenGLES + MediaPlayer 获取视频截图

概述 Android 获取视频缩略图的方法通常有: ContentResolver: 使用系统数据库MediaMetadataRetriever: 这个是android提供的类&#xff0c;用来获取本地和网络media相关文件的信息ThumbnailUtils: 是在android2.2&#xff08;api8&#xff09;之后新增的一个&#xff0c;该类为…

数字化转型背景下,高职院校计算机网络应用的革新策略

在当今信息化时代&#xff0c;计算机网络已经成为高职院校教育不可或缺的一部分&#xff0c;它不仅极大地丰富了教育资源&#xff0c;提高了交流的便捷性&#xff0c;还催生了多样化的教学模式。对于高职院校来说&#xff0c;加强计算机网络应用的建设不仅是顺应时代潮流的必然…

【K230 CanMV】图像识别-摄像头获取图像 Sensor 函数全解析

引言&#xff1a;随着图像处理技术的不断发展&#xff0c;摄像头在嵌入式系统中的应用越来越广泛&#xff0c;尤其是在智能监控、自动驾驶、机器人视觉等领域。K230作为一款高性能的嵌入式处理器&#xff0c;提供了强大的图像处理能力&#xff0c;支持多种类型的摄像头接入与图…

SQL优化与性能——数据库设计优化

数据库设计优化是提高数据库性能、确保数据一致性和支持业务增长的关键环节。无论是大型企业应用还是小型项目&#xff0c;合理的数据库设计都能够显著提升系统性能、减少冗余数据、优化查询响应时间&#xff0c;并降低维护成本。本章将深入探讨数据库设计中的几个关键技术要点…

用Python做数据分析环境搭建及工具使用(Jupyter)

目录 一、Anaconda下载、安装 二、Jupyter 打开 三、Jupyter 常用快捷键 3.1 创建控制台 3.2 命令行模式下的快捷键 3.3 运行模式下快捷键 3.4 代码模式和笔记模式 3.5 编写Python代码 一、Anaconda下载、安装 【最新最全】Anaconda安装python环境_anaconda配置python…

Jmeter测试工具的安装和使用,mac版本,jmeter版本5.2.1

Jmeter测试工具的安装和使用JSON格式请求 一、安装1、安装jdk包和设置java环境2、去官网下载Jmeter3、解压后&#xff0c;打开mac终端&#xff0c;进入apache-jmeter的bin文件开启jmeter 二、使用jmeter1、添加线程2、添加HTTP请求3、配置请求的协议、IP地址、端口号、请求方法…

基于springboot 的体质测试数据分析及可视化设计LWPPT

技术可行性&#xff1a;技术背景 本企业网站在Windows操作系统中进行开发&#xff0c;并且目前PC机的性能已经可以胜任普通网站的web服务器。系统开发所使用的技术也都是自身所具有的&#xff0c;也是当下广泛应用的技术之一。 系统的开发环境和配置都是可以自行安装的&#x…