日度归档:2018年7月23日

C++ STL容器——set

      容器用于存储数据,在STL中,set是一个类似数学中”集合”的容器,可以进行交集并集的计算,且容器中不允许出现重复元素,set在日常使用中经常见到,值得注意的是,set内部使用二叉树存储数据,运算速度很快。

参考手册:http://www.cplusplus.com/reference/set/set/

      set的声明如下,

template < class T,                        // set::key_type/value_type
           class Compare = less<T>,        // set::key_compare/value_compare
           class Alloc = allocator<T>      // set::allocator_type
           > class set;

      第一个参数T是容器类型,第二个和第三个参数都提供的默认值,其中第二个参数是 比较器,用于给容器中元素进行大小排序,默认为less<T>,也可以自己指定,第三个参数是分配器,该参数指定使用哪个分配器对象管理内存,如果省略该模板参数的值,则容器模板将默认使用allocator<T>,这个类使用new和delete

set容器的常用方法:

初始化:

set容器常用的初始化方法为:

默认初始化

使用区间初始化

使用复制构造函数初始化

#include <iostream>
#include <string>
#include <set>
#include <cmath>
 
struct Point { double x, y; };
struct PointCmp {
    bool operator()(const Point& lhs, const Point& rhs) const { 
        return std::hypot(lhs.x, lhs.y) < std::hypot(rhs.x, rhs.y); 
    }
};
 
int main()
{
  // (1) 默认初始化器!!常用
  std::set<std::string> a;
  a.insert("cat");
  a.insert("dog");
  a.insert("horse");
  for(auto& str: a) std::cout << str << ' ';
  std::cout << '\n';
 
  // (2) 迭代器初始化器!!常用//使用区间进行初始化,也可以用数组的区间进行初始化。
  std::set<std::string> b(a.find("dog"), a.end());
  for(auto& str: b) std::cout << str << ' ';
  std::cout << '\n';
 
  // (3) 复制构造函数
  std::set<std::string> c(a);
  c.insert("another horse");
  for(auto& str: c) std::cout << str << ' ';
  std::cout << '\n';
 
  // (4) 移动构造函数
  std::set<std::string> d(std::move(a));
  for(auto& str: d) std::cout << str << ' ';
  std::cout << '\n';
  std::cout << "moved-from set is ";
  for(auto& str: a) std::cout << str << ' ';
  std::cout << '\n';
 
  // (5) initializer_list 构造函数
  std::set<std::string> e {"one", "two", "three", "five", "eight"};
  for(auto& str: e) std::cout << str << ' ';
  std::cout << '\n';
 
  // 自定义比较器
  std::set<Point, PointCmp> z = {{2, 5}, {3, 4}, {1, 1}};
  z.insert({1, -1}); // 这会失败,因为 1,-1 的长度等于 1,1
  for(auto& p: z) std::cout << '(' << p.x << ',' << p.y << ") ";
  std::cout << '\n';
}




//输出:

cat dog horse 
dog horse 
another horse cat dog horse 
cat dog horse 
moved-from set is 
eight five one three two 
(1,1) (3,4) (2,5)

insert():插入元素

常用insert(A,B)//A,B分别是两个迭代器,或两个数组中的指针,把[A,B)区间的元素插入容器。

insert(E)//直接插入一个元素

 

erase():删除操作:

iterator  erase (const_iterator position);//删除迭代器指向位置的元素
size_type erase (const value_type& val);//删除这个元素
iterator  erase (const_iterator first, const_iterator last);//删除这个区间的元素

find():查找元素

如果找到了,则返回指向这个元素的迭代器,如果没有找到,则返回一个指向最后一个元素尾部的迭代器.   (end()的返回值,这个迭代器指向最后一个元素的下一个元素,所以无效)

// set::find
#include <iostream>
#include <set>

int main ()
{
  std::set<int> myset;
  std::set<int>::iterator it;

  // set some initial values:
  for (int i=1; i<=5; i++) myset.insert(i*10);    // set: 10 20 30 40 50

  it=myset.find(20);
  myset.erase (it);
  myset.erase (myset.find(40));

  std::cout << "myset contains:";
  for (it=myset.begin(); it!=myset.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

 


    begin()//返回一个指向元素开头的迭代器(ps:关于迭代器,我们可以把它当作指针)

    end()//返回一个指向最后一个元素尾部的迭代器

// set::begin/end
#include <iostream>
#include <set>

int main ()
{
  int myints[] = {75,23,65,42,13};
  std::set<int> myset (myints,myints+5);//使用数组初始化set容器中的元素

  std::cout << "myset contains:";
  for (std::set<int>::iterator it=myset.begin(); it!=myset.end(); ++it)
    std::cout << ' ' << *it;

  std::cout << '\n';

  return 0;
}

//输出:myset contains: 13 23 42 65 75

rbegin()/rend():返回反向迭代器

// set::rbegin/rend
#include <iostream>
#include <set>

int main ()
{
  int myints[] = {21,64,17,78,49};
  std::set<int> myset (myints,myints+5);

  std::set<int>::reverse_iterator rit;

  std::cout << "myset contains:";
  for (rit=myset.rbegin(); rit != myset.rend(); ++rit)
    std::cout << ' ' << *rit;

  std::cout << '\n';

  return 0;
}

//输出:myset contains: 78 64 49 21 17 
//参数中默认的比较器是从小到大排列的,所以这里反向输出的容器元素的值

cbegin()/cend():返回一个const的迭代器

crbegin()/crend():返回const的反向迭代器


empty()//测试容器是否为空,为空则返回true.

size()//返回容器有多少元素.

max_size()//返回容器存储元素的最大值.

 



最后介绍一下set在集合意义上的操作

set_union()//求并集

set_intersection//交集

set_difference//差集

这三个函数的接口是相同的,他们都有5个参数,分别是:第一个集合的区间,第二个集合的区间,输出迭代器,这个迭代器指出要将操作的结果输出到哪里。

今天写累了,明天再写

待更新