1. 程式人生 > >我不熟悉的set

我不熟悉的set

我不熟悉的set

同樣的我著重介紹那些我不怎麼用到的系列,同時,常用的我就點一下。

我們都知道set底層是用紅黑樹實現的,紅黑樹是一種已排序的樹,所以我們通過迭代器來訪問節點元素的時候,並不可以改變它,如果隨意改變,那排序規則就亂套了。

講API之前,現介紹一個 對組(pair) 的概念。

對組(pair)將一對值組合成一個值,這一對值可以具有不同的資料型別,兩個值可以分別用pair的兩個公有屬性first和second訪問。

建立對組的方法

一、使用拷貝構造

pair<string, int> pair1(string("name"), 20);
cout << pair1.first << endl; //訪問pair第一個值
cout << pair1.second << endl;//訪問pair第二個值

二、使用make_pair

pair<string, int> pair2 = make_pair("name", 30);
cout << pair2.first << endl;
cout << pair2.second << endl;

對組可以方便的將不同資料型別作為返回值,一次返回兩個數值。

構造,賦值和大小操作

set<T> st;          //set預設建構函式。
set(const set &st); //拷貝建構函式
swap(set st);       //交換兩個集合容器
size();             //返回容器中元素的數目
empty();            //判斷容器是否為空

與前幾篇說的一致。

插入與刪除

pair<iterator,bool> insert(elem);  //在容器中插入元素。
void insert(beg,end)     //插入[beg,end)範圍元素
iterator erase(pos);     //刪除pos迭代器所指的元素,返回下一個元素的迭代器。
iterator erase(beg, end);//刪除區間[beg,end)的所有元素 ,返回下一個元素的迭代器。
size_type erase(elem);   //刪除容器中值為elem的元素。
void clear();            //清除所有元素

這邊強調一下erase和insert:

關於erase:

  • 既可以刪除迭代器指向的元素,也可以刪除指定的元素值。與list一致。
  • 刪除迭代器的時候返回指向的下一個迭代器。
  • 刪除指定元素的時候,返回的是這個元素在容器中的個數。(set為0或1,multiset可以大於1)

關於insert:

  • 唯一的一個插入元素的動作。
  • 插入元素時,返回一個對組。第一個成員是指向新插入值或已存在的這個值的迭代器,第二個成員表示插入成功與否(不存在的,新插入的為真,已存在的不需新插入為假)。
  • 範圍插入的時候,沒有返回值。

查詢函式

這才是今天的重點。

iterator find(key);  //查詢鍵key是否存在,若存在,返回該鍵的元素的迭代器;若不存在,返回set.end();
size_type count(key); //查詢鍵key的元素個數
iterator lower_bound(keyElem);//返回第一個key>=keyElem元素的迭代器。
iterator upper_bound(keyElem);//返回第一個key>keyElem元素的迭代器。
pair<iterator,iterator> equal_range(keyElem);//返回容器中key與keyElem相等的上下限的兩個迭代器。

find函式

find函式,實際上是在紅黑樹中進行二叉搜尋,如果找到了就返回相應位置迭代器,找不到就返回尾後迭代器end().

count函式

根據set不能重複的性質,count非零即一。

lower_bound,upper_bound和equal_range函式

很直接的,lower就是返回第一個大於等於指定元素的迭代器,而upper就是返回第一個大於指定元素的迭代器。如下所示:

int main()
{
    set<int> s;
    s.insert(2);
    s.insert(4);
    s.insert(9);
    s.insert(10);
    s.insert(20);
    auto it1 = s.lower_bound(9);
    auto it2 = s.upper_bound(9);
    cout << "*it1=" << *it1 << " *it2=" << *it2 << endl;
    return 0;
}

我們輸出結果為:

*it1=9 *it2=10

由此可以清楚看出這兩個函式的作用。

接下來我們介紹equal_range函式。equal_range的作用就是返回查詢到的元素的上下限迭代器,同樣遵守左閉右開的原則。而這正好是我們lower_bound和upper_bound的返回值。所以,我們可以將equal_range的返回值看做是返回一個存著lower_bound和upper_bound的返回值的對組。

我們可以驗證:

int main()
{
    //multiset<int> s;
    set<int> s;
    s.insert(2);
    s.insert(4);
    s.insert(9);
    s.insert(9);
    s.insert(9);
    s.insert(10);
    s.insert(20);
    auto it1 = s.lower_bound(9);
    auto it2 = s.upper_bound(9);
    auto pair = s.equal_range(9);

    if (pair.first == it1 && pair.second == it2)
        cout << "equal_range pair == lower_bound & upper_bound" << endl;
    
    return 0;
}

最後我們成功輸出了

"equal_range pair == lower_bound & upper_bound"

set的排序規則

set預設是從小到大排序的,當我們要從大到小排序或者用自定義資料排序的時候,我們就要指定排序規則,同樣也是使用仿函式實現:

//functor為仿函式
set<int,functor> s;
...

自己寫一個仿函式即可。可參照 我不熟悉的list .

不支援回撥函式。

速記:因為set用紅黑樹實現,插入即排序,排序一旦建立不能更改,所以要在建立set的時候就指定排序規則,而不是插入完了之後再指定。

由於set的特殊性,插入即排序建立。故有此要求。