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()返回值相同

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章