zoukankan      html  css  js  c++  java
  • c++中std::set自定义去重和排序函数

    c++中std::set自定义去重和排序函数

     

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

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

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

     
     1 #include <iostream>
     2 #include <set>
     3 using namespace std;
     4 void main()
     5 {
     6     std::set<int> mySet;    // 直接定义内置类型set集合
     7     mySet.insert(10);       // 默认比较函数为less
     8     mySet.insert(20);       // 从小到大排序
     9     for(auto it:mySet)    
    10     {
    11         std::cout<<it<<std::endl;
    12     }
    13     std::cout<<"end"<<std::endl;
    14 
    15 }
     
    结果如下:
    output: 10 20 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(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

             2.2 重载()运算符

         具体代码如下:

     
     1 #include <iostream>
     2 #include <set>
     3 using namespace std;
     4 struct song
     5 {
     6     int m_id;
     7     int m_hot;
     8     song(int id,int hot)
     9     {
    10 
    11         this->m_id = id;
    12         this->m_hot = hot;
    13     }
    14     /*
    15     bool operator<(const struct song & right)const   //重载<运算符
    16     {
    17         if(this->m_id == right.m_id)     //根据id去重
    18             return false;
    19         else
    20         {
    21             if(this->m_hot != right.m_hot)
    22             {
    23                 return this->m_hot > right.m_hot;      //降序
    24             }
    25             else
    26             {
    27                 return this->m_id > right.m_id;     
    28             }
    29         }
    30     }
    31     */
    32 };
    33 struct comp   
    34 {
    35     bool operator()(struct song left,struct song  right)  //重载()运算符
    36     {
    37 
    38         if(left.m_id == right.m_id)     //根据id去重
    39             return false;
    40         else
    41         {
    42             if(left.m_hot != right.m_hot)
    43             {
    44                 return left.m_hot > right.m_hot;      //降序
    45             }
    46             else
    47             {
    48                 return left.m_id > right.m_id;     
    49             }
    50 
    51         }
    52     }
    53 
    54 };
    55 void main()
    56 {
    57     std::set<song,comp> mySet;      //写法和2.1中的的区别
    58     song s1(10,100);
    59     song s2(20,200);
    60     song s3(20,300);
    61     song s4(30,200);
    62     mySet.insert(s1);    //插入s1
    63     mySet.insert(s2);    //插入s2
    64     mySet.insert(s3);    //s3和s2的id相同,不插入
    65     mySet.insert(s4);    //插入s4
    66     for(auto it:mySet)
    67     {
    68         std::cout<<"id:"<<it.m_id<<",hot:"<<it.m_hot<<std::endl;
    69     }
    70     std::cout<<"end"<<std::endl;
    71 };
     
    结果如下:
    id:30,hot : 200
    id:20,hot : 200
    id:10,hot : 100
    end
     
  • 相关阅读:
    获取页面元素的xpath,验证自己写的xpath,不用工具不用插件,看完这篇保证你学会!
    Python判断IEDriverServer是否最新版本并自动更新
    Python判断软件版本号的大小
    selenium通过加载火狐Firefox配置文件FirefoxProfile,实现免登陆访问网站
    mysql查询每个学生的各科成绩,以及总分和平均分
    selenium点击(click)页面元素没有反应(报element not interactable)的一个案例
    Python查询物理主机上所有虚拟机并保存为excel,通过标记批量启动
    Python线程池下载txt
    Python自动下载最新的chromedriver
    django的url的name参数的意义
  • 原文地址:https://www.cnblogs.com/leijiangtao/p/12057368.html
Copyright © 2011-2022 走看看