C++容器基础之 set详解

一、set概述

         set是一个关联式容器,set中,元素都是唯一的,并且在往set中添加元素的时候,会根据元素的值进行自动排序。其内部采用的数据结构是红黑树,红黑树是一种非常高效的平衡检索二叉树。读者若有兴趣,可自行查阅相关资料。set的插入和搜索速度是很快的,set中使用的是二分查找,是log的关系。比如有16个元素的set,最多需要查找4次,有10000个元素,最多需要查找14次,就算元素再增加一倍,达到20000个,最多需要查找15次,也只是多了一次查找而已。

1、为什么set插入、删除的效率比较高?

      对于set来讲,不需要内存拷贝和内存移动,set中元素是以节点的方式存储的,插入数据的时候只需要做相应的节点变换即可,删除操作也是类似的,与内存拷贝、内存移动没有任何关系。

2、每次insert后,之前保存的iterator是否会失效?

     插入元素的时候,并没有涉及到内存拷贝和内存移动,内存没有变,故不会失效。

  

二、set的使用

       set内部元素是有序的,如果存放的是内置数据类型,会按照默认排序。如果存放自定义数据类型则需要自定义排序。当然,内置数据类型也可以使用自定义排序。

1、自定义排序

      方式一:重载<

      

class Student{
public:
    std::string name_;
    int age_;
    Student(std::string name, int age):name_(name),age_(age){}
    Student(){}

    bool operator < (const Student &s) const {
        if(name_ != s.name_){
            return name_ < s.name_;
        }else{
            return age_ < s.age_;
        }
    }

    std::string show(){
        return "name:" + name_ + ", age:" + std::to_string(age_);
    }

};

int main(int argc, char *argv[]) {

    set<Student> s;
    s.emplace(Student("Danney", 22));
    s.emplace(Student("LiMing", 20));
    s.emplace(Student("LiMing", 18));
    for(auto it : s){
        cout << it.show() << endl;

    }
    return 0;
}

方式二:重载()

class Student{
public:
    std::string name_;
    int age_;
    Student(std::string name, int age):name_(name),age_(age){}
    Student(){}
    std::string show(){
        return "name:" + name_ + ", age:" + std::to_string(age_);
    }
};

class Comp{
public:
    bool operator () (const Student &left, const Student &right){
        if(left.name_ != right.name_){
            return left.name_ < right.name_;
        }else{
            return left.age_ < right.age_;
        }
    }
};

int main(int argc, char *argv[]) {

    set<Student, Comp> s;
    s.emplace(Student("Danney", 22));
    s.emplace(Student("LiMing", 20));
    s.emplace(Student("LiMing", 18));

    for(auto it : s){
        cout << it.show() << endl;
    }
    return 0;
}

 方式三:

  

class Student{
public:
    std::string name_;
    int age_;
    Student(std::string name, int age):name_(name),age_(age){}
    Student(){}

    std::string show(){
        return "name:" + name_ + ", age:" + std::to_string(age_);
    }
};

bool comp (const Student &left, const Student &right){
    if(left.name_ != right.name_){
        return left.name_ < right.name_;
    }else{
        return left.age_ < right.age_;
    }
}
int main(int argc, char *argv[]) {

    set<Student, decltype(comp)*> s(comp);
    s.emplace(Student("Janney", 23));
    s.emplace(Student("Danney", 22));
    s.emplace(Student("LiMing", 20));
    s.emplace(Student("LiMing", 18));

    for(auto it : s){
        cout << it.show() << endl;

    }
    return 0;
}

    2、添加元素:三种方式    

    set<int> sInt;
    //元素添加
    //1、返回pair对象,second表示是否添加成功
    pair<set<int>::iterator, bool > isSu = sInt.insert(5);
    if(isSu.second){
        cout << "successful!" << endl;
    }
    //2、在iterator前插入元素 insert(&pos, value),返回新元素的位置
    sInt.insert(isSu.first,9);
    //3、添加区间,将区间[&first, &last)区间内的元素添加到set中
    int array[] = {4, 10, 6};
    sInt.insert(array, array+3);

  3、删除元素:四种方式

    //元素删除
    //1、erase(value),返回移除元素的个数
    auto num = sInt.erase(6);
    cout << "移除元素个数:" << num << endl;
    //2、erase(&pos),移除pos上的元素,无返回值
    auto iter = sInt.begin();
    sInt.erase(iter);
    for(auto it : sInt){
        cout << it << ", ";
    }
    //3、erase(&first, &last),移除[&first, &last)区间内的元素
    sInt.erase(sInt.begin(), sInt.end());
    cout << endl << "after [fir, last) : " << endl;
    for(auto it : sInt){
        cout << it << ", ";
    }
    //4、移除所有元素
    sInt.clear();
    cout << endl << "after clear : " << endl;
    for(auto it : sInt){
        cout << it << ", ";
    }

4、查找

    //查找
    //1、count(value),返回value的个数
    cout << sInt.count(10) << endl;
    //2、iterator find(value),返回value的位置,如果找不到,则返回end()
    auto res_find_f = sInt.find(10);
    if(res_find_f == sInt.end()){
        cout << "未找到" << endl;
    }else{
        cout << "已找到" << endl;

    }
    auto res_find_s = sInt.find(20);
    if(res_find_s == sInt.end()){
        cout << "未找到" << endl;
    }else{
        cout << "已找到" << endl;

    }

 5、其他

   begin():返回set的第一个元素

   end():返回set最后一个元素的下一个位置

   empty():判断是否为空

   max_size():返回set中可能包含的元素个数最大值

   size():返回当前元素个数

   rbegin():与end()返回值相同

   rend():与begin()返回值相同

猜你喜欢

转载自blog.csdn.net/yu532164710/article/details/105194036