来自网上的一篇c++中std::set自定义去重和排序函数博文中的去重方法存在严重错误(坑害了我很久。。。。。)
其中的方法二:利用重载 < 操作符或重载 () 运算符实现自定义类的排序和去重问题,代码如下:
#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(10,100);
song s2(20,200);
song s3(20,300);
song s4(30,200);
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
代码利用重载 < 操作符,按照song.id查重,按照song.hot排序。然而看似完美的结果其实存在错误,只需要稍微改变一下插入的顺序和输入的数据,就会出现错误:
int main()
{
std::set<song> mySet;
song s1(10,100);
song s2(20,200);
song s3(30,200);
song s4(10,300);
mySet.insert(s1); //插入s1
mySet.insert(s2); //插入s2
mySet.insert(s3); //插入s3
mySet.insert(s4); //s4和s1的id相同
for(auto it:mySet)
{
std::cout<<"id:"<<it.m_id<<",hot:"<<it.m_hot<<std::endl;
}
std::cout<<"end"<<std::endl;
return 0;
};
输出的结果为:
id:10,hot:300
id:30,hot:200
id:20,hot:200
id:10,hot:100
end
这里重复插入了两个 id 为 10 的变量,所以该代码其实并不能正确的去重。
大概猜测其原因是,代码按照song.id查重,却按照song.hot排序,而insert方法不是遍历整个容器,而是红黑树的插入操作,因此insert操作按照song.hot排序查找到合适的位置就会直接插入,而不会遍历整个容器去重。
因此,重载自定义类的比较操作只能按照单一的标准进行排序和去重 。