c++中的std::set,是基于红黑树的平衡二叉树的数据结构实现的一种容器,因为其中所包含的元素的值是唯一的,因此主要用于去重和排序。这篇文章的目的在于探讨和分享如何正确使用std::set实现去重和排序功能。

  1.方法一:使用std::set内置的less比较函数(直接定义内置类型的set对象)

   这种方法适用于:1)比较int、char等内置类型。2)只能针对某一个内置类型去重和排序:如果想通过id(int)去重,并通过hot(int)排序,该种方法就束手无策了。代码如下:

 #include <iostream>
#include <set>
using namespace std;
void main()
{
std::set<int> mySet; // 直接定义内置类型set集合
mySet.insert(); // 默认比较函数为less
mySet.insert(); // 从小到大排序
for(auto it:mySet)
{
std::cout<<it<<std::endl;
}
std::cout<<"end"<<std::endl; }
结果如下:
output: end

  2.方法二:自定义类(结构体)比较函数

    前文提到:直接定义内置类型的set对象,即使用std::set内置的默认的less比较函数,可能不能满足我们的实际需求。例如:现在有一批结构体对象,需要将其插入set集合,并按照id去重,按照热度hot进行排序。这个时候,就需要重新自定义比较函数了。有两种方法可以自定义比较函数:

  2.1 重载<操作符

    为甚么要重载<运算符呢?能不能重载"<="或者">="运算符?答案是不可以。几乎所有的方法或容器都需要排序来满足数学意义上的标准严格弱序化,否则这些方法或容器的行为将不可预知。假设f(x,y)是一个比较函数。 如果该函数满足如下条件则它是严格弱序化的。

     1.f(x,x) = false;

    2. if f(x,y) then !f(y,x)

    3.if f(x,y) and f(y,z) then f(x,z)

    4. if !f(x,y)&&!f(y,x) then x==y; if x==y and y==z then x==z;

看上去有点晕乎,不过不用担心,只要你的比较方法能够满足对相等元素永远返回false(记住一个准则:永远让比较函数对相同元素返回false),那你的方法就满足要求了。

    其实,set容器在判定已有元素a和新插入元素b是否相等时,是这么做的:1)将a作为左操作数,b作为有操作数,调用比较函数,并返回比较值  2)将b作为左操作数,a作为有操作数,再调用一次比较函数,并返回比较值。如果1、2两步的返回值都是false,则认为a、b是相等的,则b不会被插入set容器中;如果1、2两步的返回值都是true,则可能发生未知行为,因此,记住一个准则:永远让比较函数对相同元素返回false。

#include <iostream>
#include <set>
using namespace std;
struct song
{
int m_id;
int m_hot;
song(int id,int hot)
{ this->m_id = id;
this->m_hot = hot;
}
bool operator<(const struct song & right)const //重载<运算符
{
if(this->m_id == right.m_id) //根据id去重
return false;
else
{
if(this->m_hot != right.m_hot)
{
return this->m_hot > right.m_hot; //降序
}
else
{
return this->m_id > right.m_id;
}
}
}
};
void main()
{
std::set<song> mySet;
song s1(,);
song s2(,);
song s3(,);
song s4(,);
mySet.insert(s1); //插入s1
mySet.insert(s2); //插入s2
mySet.insert(s3); //s3和s2的id相同,不插入
mySet.insert(s4); //插入s4
for(auto it:mySet)
{
std::cout<<"id:"<<it.m_id<<",hot:"<<it.m_hot<<std::endl;
}
std::cout<<"end"<<std::endl;
};
结果如下:
id:,hot :
id:,hot :
id:,hot : 100
end

2.2 重载()运算符

     具体代码如下:

 #include <iostream>
#include <set>
using namespace std;
struct song
{
int m_id;
int m_hot;
song(int id,int hot)
{ this->m_id = id;
this->m_hot = hot;
}
/*
bool operator<(const struct song & right)const //重载<运算符
{
if(this->m_id == right.m_id) //根据id去重
return false;
else
{
if(this->m_hot != right.m_hot)
{
return this->m_hot > right.m_hot; //降序
}
else
{
return this->m_id > right.m_id;
}
}
}
*/
};
struct comp
{
bool operator()(struct song left,struct song right) //重载()运算符
{ if(left.m_id == right.m_id) //根据id去重
return false;
else
{
if(left.m_hot != right.m_hot)
{
return left.m_hot > right.m_hot; //降序
}
else
{
return left.m_id > right.m_id;
} }
} };
void main()
{
std::set<song,comp> mySet; //写法和2.1中的的区别
song s1(,);
song s2(,);
song s3(,);
song s4(,);
mySet.insert(s1); //插入s1
mySet.insert(s2); //插入s2
mySet.insert(s3); //s3和s2的id相同,不插入
mySet.insert(s4); //插入s4
for(auto it:mySet)
{
std::cout<<"id:"<<it.m_id<<",hot:"<<it.m_hot<<std::endl;
}
std::cout<<"end"<<std::endl;
};
结果如下:
id:30,hot : 200
id:20,hot : 200
id:10,hot : 100
end

    

c++中std::set自定义去重和排序函数的更多相关文章

  1. python中sorted()和set()去重,排序

    前言 在看一个聊天机器人的神经网络模型训练前准备训练数据,需要对训练材料做处理(转化成张量)需要先提炼词干,然后对词干做去重和排序 words = sorted(list(set(words))) 对 ...

  2. FCL源码中数组类型的学习及排序函数Sort函数的分析

    Array 是所有数组的基类ArrayList 解决了所有Array 类的缺点    能动态扩容, 但是类型不安全的,而是会有装箱与拆箱的性能开销List<T> 则是解决了ArrayLis ...

  3. 重写Oracle的wm_concat函数,自定义分隔符、排序

    oracle中,wm_concat函数是一个聚合函数,和mysql中的group_concat函数类似,不过group_concat函数比较强大,可以定义分隔符和排序,当然所谓强大是相对的,这里假使我 ...

  4. MapReduce自定义二次排序流程

    每一条记录开始是进入到map函数进行处理,处理完了之后立马就入自定义分区函数中对其进行分区,当所有输入数据经过map函数和分区函数处理完之后,就调用自定义二次排序函数对其进行排序. MapReduce ...

  5. PHP常用数字函数以及排序函数

    一:数字函数 .ceil() 进一取整 示例:ceil(0.9) 结果为1 .abs() 绝对值 示例:abs(-1) 结果为1 .rand() 随机数 示例:rand(1. 100) 1到100 以 ...

  6. java中List对象列表去重或取出以及排序

    面试碰到几次list的去重和排序.下面介绍一种做法: 1. list去重 1.1 实体类Student List<Student>容量10k以上,要求去重复.这里Student的重复标准是 ...

  7. 一个std::sort 自定义比较排序函数 crash的分析过程

    两年未写总结博客,今天先来练练手,总结最近遇到的一个crash case. 注意:以下的分析都基于GCC4.4.6 一.解决crash 我们有一个复杂的排序,涉及到很多个因子,使用自定义排序函数的st ...

  8. 【转载】C#中自定义Sort的排序规则IComparable接口

    C#中的List集合在排序的时候,如果不使用Lambda表达式进行排序的话,一般调用Sort()方法进行排序,如果希望Sort()方法排序后的结果跟我们预想的效果一致或者按照我们自定义的规则排序,则需 ...

  9. vector中数据进行去重和排序

    , , , , , , ,}; std::vector<int> vec(a, a+sizeof(a)/sizeof(int) ); std::sort(vec.begin(), vec. ...

随机推荐

  1. Eclipse查看方法/类调用的方法

    1.(首推)双击选中该方法/类,[Ctrl]+[Alt]+[H](Open Call Hierarchy) 2.(次推)选中该方法/类,[Ctrl]+[Shift]+[G](References) 3 ...

  2. Oracle Multitenant Environment (一) About

    About oracle mulittenant environment The multitenant architecture enables an Oracle database to func ...

  3. Eclipse Java Build Path详解

    Eclipse Java Build Path详解 1.设置"source folder"与"output folder". * source folder:存 ...

  4. TI C66x DSP 系统events及其应用 - 5.11(中断控制寄存器)

    C66x DSP运行中断的简要流程: 1.使能了全局中断和子中断.假设硬件检測到中断发生,那么CPU就要跳转. 2.软件把CPU内部的A,B类寄存器的值等推入堆栈保存,把当前PC寄存器的值放入IRP寄 ...

  5. 为什么使用do{}while(0)?

    近期学习Cocos2d-x,看到不少使用do{}while(0)的宏定义,如: #define CC_SAFE_DELETE(p) do { delete (p); (p) = nullptr; } ...

  6. Linux系统centos7+VMwareWorkstation创建共享文件夹错误解决方法集锦

    在创建共享文件夹过程中出现了多种错误,多次尝试后终于解决了. 1.直接找到VMware Tools压缩包的位置:/run/media/wxy/VMware\ Tools /**省去了创建光盘挂载点:m ...

  7. 使用git命令 (git reset --hard HEAD) 回退版本信息

    Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100 ...

  8. POJ2985 The k-th Largest Group treap

    POJ2985 比较简单的平衡树题目 树内不要添加容量为1的节点 否则会超时. #include<iostream> #include<cstdio> #include< ...

  9. bzoj4403 序列统计——组合数学

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4403 一开始想了个 O(n) 的做法,不行啊... O(n)想法是这样的:先考虑递推,设 f ...

  10. ngRoute (angular-route.js) 和 ui-router (angular-ui-router.js) 模块有什么不同呢?

    ngRoute (angular-route.js) 和 ui-router (angular-ui-router.js) 模块有什么不同呢? 很多文章中都有说道:当时ngRoute在路由配置时用$r ...