C++ STL/ (7) set

  • 预备知识

    • 二叉树
      树的任意一个结点都最多只有两个结点。
    • 二叉搜索树
      树的任意一个结点的值都比该结点的左子树中的任意一个结点的值大;同时比该结点右子树中的任意结点的值小。
    • 平衡二叉树(红黑树RB-tree是平衡二叉树的一种)
      针对二叉搜索树搜索性能不稳定这个问题。我们跟进一步发明了平衡二叉树。平衡二叉树能保证左右子树的高度差小于等于1。这样在查找特点值时不会出现查找左右两子树的开销相差太大的情况。
  • set/multiset基本概念

    • 什么是set/multiset?
      set和multiset是关联型容器。
      • set/multiset的特点
        • set容器中的元素会按元素值的大小进行排序,所以set容器对查找很支持。
        • set中不允许有重复的元素;而multiset允许
    • set/multiset功能
      下图所示:
      set
    • set/multiset实现原理
      • set是基于红黑树(红黑树是一种二叉树)实现的关联型容器
  • set/multiset的API

    • 初始化

      set <int> s1;
      multiset<int> s2;
      s1.insert(1);
      set<int> s3(s1);
      set<int> s4=s3;
    • 赋值

          //=运算符重载
          //swap()
    • 元素访问

      //只能通过iterator访问元素,且不能改变
      set <int> s1;
      s1.insert(1);
      s1.insert(9);
      s1.insert(5);
      s1.insert(4);
      s1.insert(7);
      s1.insert(8);
      set<int>:: iterator i=s1.begin();
      while(i!=s1.end()){
          cout<<*i<<" ";
          i++;
      }
      cout<<endl;
      
    • set/multiset大小

      //size()
      //empty()
    • set/multiset插入和删除

      //insert(ele)
      //erase(iter_start,iter_end)
      //erase(iter_pos)
      //erase(ele)
      //clear()
    • set/multiset查找

      //find(ele)
      //lower_bound(keyele);
      //upper_bound(keyele);
      //equal_range(keyele);

  • 我们知道set默认的排序方式是从小到大。那么我们是不是可以通过某种方法让set实现从大到小的排序呢?
    要实现这个功能就要先理解函数对象的概念。

    • 什么是函数对象?
      函数对象是一个对象,其使用和函数的形式相同,故称为函数对象。

      • 定义
      class Mycompare{
      public:
          bool operator() (int val1,int val2){
              return val1>val2;
          }
      };
      
      Mycompare M_com;
      M_com(3,5); //该对象调用重载运算符(),其形式和函数的用法相同。
    • 函数对象的使用
      C++ STL中已经封装了很多的函数对象在头文件functional中。下面我们来看一个从大到小给set容器排序的例子。

      
      #include <iostream>
      
      
      #include <set>
      
      
      #include <functional>
      
      
      #include <algorithm>
      
      
      using namespace std;
      
      void printset(set<int,greater<int>> & s);
      
      int main(){
          set <int,greater<int>> s1;
          s1.insert(1);
          s1.insert(9);
          s1.insert(5);
          s1.insert(4);
          s1.insert(7);
          s1.insert(8);
          printset(s1);
      
          return 0;
      }
      
      void printset(set<int,greater<int>> & s){
          set<int>::iterator i = s.begin();
          while (i != s.end()){
              cout << *i << " ";
              i++;
          }
          cout << endl;
      }
    • 自定义函数对象使用

      
      #include <iostream>
      
      
      #include <set>
      
      
      #include <functional>
      
      
      #include <algorithm>
      
      
      using namespace std;
      
      class Mycompare{
      public:
          bool operator() (int val1, int val2){
              return val1 > val2;
          }
      };
      
      
      
      void printset(set<int,Mycompare> & s);
      
      int main(){
          //set <int,greater<int>> s1;
          set <int,Mycompare> s1;
          s1.insert(1);
          s1.insert(9);
          s1.insert(5);
          s1.insert(4);
          s1.insert(7);
          s1.insert(8);
          printset(s1);
      
          return 0;
      }
      
      void printset(set<int,Mycompare> & s){
          set<int>::iterator i = s.begin();
          while (i != s.end()){
              cout << *i << " ";
              i++;
          }
          cout << endl;
      }

      我们可能发现了,使用functional自带的函数对象格式是greater;而自定义的函数对象则是Mycompare没有<>。我们可以使用template来实现和functional库文件中一样的函数对象格式。修改后的程序如下:

      
      #include <iostream>
      
      
      #include <set>
      
      
      #include <functional>
      
      
      #include <algorithm>
      
      
      using namespace std;
      
      template <class T>
      class Mycompare{
      public:
          bool operator() (T val1, T val2){
              return val1 > val2;
          }
      };
      
      
      
      void printset(set<int,Mycompare<int>> & s);
      
      int main(){
          //set <int,greater<int>> s1;
          set <int,Mycompare<int>> s1;
          s1.insert(1);
          s1.insert(9);
          s1.insert(5);
          s1.insert(4);
          s1.insert(7);
          s1.insert(8);
          printset(s1);
      
          return 0;
      }
      
      void printset(set<int,Mycompare<int>> & s){
          set<int>::iterator i = s.begin();
          while (i != s.end()){
              cout << *i << " ";
              i++;
          }
          cout << endl;
      }
      

  • set容器也可以存放对象

    //新建一个类
    class Teacher{
    public:
        int id;
        int age;
        Teacher(int id, int age) :id(id), age(age){}
    };
    //写一个类的排序方法
    class Compare_teacher{
    public:
        bool operator()(Teacher t1, Teacher t2){
            return t1.id < t2.id;
        }
    };
    
    //main函数部分
    Teacher t1(1, 2), t2(3, 4), t3(5, 6);
    set<Teacher,Compare_teacher>  s_t;    //如果是set<Teacher> s_t;会是什么情况?
    s_t.insert(t1);
    s_t.insert(t2);
    s_t.insert(t3);
    set<Teacher, Compare_teacher>::iterator i = s_t.begin();
    while (i != s_t.end()){
        cout << "id is : " << i->id << " age is : " << i->age << endl;
        i++;
    }
    

  • set 容器的最重要的方法find()

    set<Teacher, Compare_teacher>::iterator pos = s_t.find(t2);//find查找对象
    cout << "id is:"<<pos->id<<"age is:"<<pos->age << endl;
    
    set<Teacher, Compare_teacher>::iterator pos2 = s_t.find(Teacher(30,4));//find查找匿名对象
    
    if (pos2 != s_t.end()){
        cout << "id is:" << pos2->id << "age is:" << pos2->age << endl;
    }
    else{
        cout << "can not find!!" << endl;
    }
  • upper_bound &lower_bound &equal_range的使用
    我们知道set容器的主要功能之一就是查找,那么有关查找的方法就很重要了。
    想要了解上述三种方法的使用,我们先要了解对组的概念。

    • 什么是对组?
      我们在使用某些变量的时候,往往希望变量能够接收两个变量的值;比如:函数传递返回值。如果使用结构体或者类去实现又很繁琐。这个时候就需要对组这个工具了。

      • 如何定义一个对组?
        三种初始化的方法。对组用方法.first来访问第一个元素;用.second方法来访问第二个元素。
      pair<int, string> my_pair(10, "abc");
      cout << "my_pair first is :" << my_pair.first << " my_pair second is :" << my_pair.second.c_str() << endl;
      pair<int, string> my_pair2 = make_pair(20, "ABC");
      cout << "my_pair2 first is :" << my_pair2.first << " my_pair2 second is :" << my_pair2.second.c_str() << endl;
      auto my_pair3 = my_pair;
      cout << "my_pair3 first is :" << my_pair3.first << " my_pair3 second is:" << my_pair3.second.c_str() << endl;
    • set的查找方法

      
      #include <iostream>
      
      
      #include <set>
      
      
      #include <algorithm>
      
      
      using namespace std;
      
      int main(){
      
          set <int> s1;
          s1.insert(10);
          s1.insert(34);
          s1.insert(2);
          s1.insert(30);
          s1.insert(5);
      
          set<int>::iterator i = s1.lower_bound(5);  //>=5
          cout << *i << endl;  //output 5
          set<int>::iterator j = s1.upper_bound(5);    //>5
          cout << *j << endl;   //output 10
      
          set<int>::iterator p, q;
          p = s1.equal_range(5).first;    //相当于 lower_bound
          q = s1.equal_range(5).second;   //相当于 upper_bound
      
          cout << *p << " " << *q << endl;
      
          return 0;
      }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值