c++ 11标准模板(STL) std::set(二)

修改器

1、clear      清除内容        (公开成员函数)  

std::set<Key,Compare,Allocator>::clear
void clear();                        (C++11 前) 
void clear() noexcept;                 (C++11 起) 

从容器擦除所有元素。此调用后 size() 返回零。

非法化任何指代所含元素的引用、指针或迭代器。任何尾后迭代器保持合法。

参数                  (无)

返回值               (无)

复杂度                与容器大小,即元素数成线性。

用例

    std::set<char> set1{'A', 'B', 'C', 'D', 'E'};
    std::cout << "set1 size: " << set1.size() << std::endl;
    set1.clear();
    std::cout << "clear after set1 size: " << set1.size() << std::endl;

2、insert                        插入元素或结点 (C++17 起)(公开成员函数)

插入元素到容器,若容器未含拥有等价关键的元素。

std::set<Key,Compare,Allocator>::insert

1-2) 插入 value 。 

1-2) 返回由指向被插入元素(或阻止插入的元素)的迭代器和若插入发生则设为 true 的 bool 值。

std::pair<iterator,bool> insert( const value_type& value );    (1)  
std::pair<iterator,bool> insert( value_type&& value );         (2) (C++11 起) 

3-4) 插入 value 到尽可能接近,正好前于(C++11 起) hint 的位置。

3-4) 返回指向被插入元素,或阻止插入的元素的迭代器。

(3)
iterator insert( iterator hint, const value_type& value );        (C++11 前) 
iterator insert( const_iterator hint, const value_type& value );  (C++11 起) 

(4)
iterator insert( const_iterator hint, value_type&& value );       (C++11 起) 

5) 插入来自范围 [first, last) 的元素。 若范围中的多个元素拥有比较等价的关键,则插入哪个元素是未指定的

template< class InputIt >
void insert( InputIt first, InputIt last );                 (5) 

6) 插入来自 initializer_list ilist 的元素。 若范围中的多个元素拥有比较等价的关键,则插入哪个元素是未指定的

void insert( std::initializer_list<value_type> ilist );    (6) (C++11 起) 

参数

hint

用作提示从何处开始搜索的迭代器 (C++11 前)
指向新元素将被插入位置之前的迭代器 (C++11 起)
value 要插入的元素值
first, last 要插入的元素范围
ilist 插入值来源的 initializer_list
nh 兼容的结点把柄
类型要求
- InputIt 必须满足遗留输入迭代器 (LegacyInputIterator) 的要求。

异常

1-4) 若任何操作抛异常,则插入无效果。

复杂度

1-2) 与容器大小成对数, O(log(size()))

3-4) 若插入恰好发生在正好后于 hint 的位置,则为均摊常数,否则与容器大小成对数。(C++11 前)

3-4) 若插入恰好发生在正好先于 hint 的位置,则为均摊常数,否则与容器大小成对数。(C++11 起)

5-6) O(N*log(size() + N)) ,其中 N 是要插入的元素数。

有提示插入 (3,4) 不返回 bool ,这是为了与顺序容器上的定位插入,如 std::vector::insert 签名兼容。这使得可以创建泛型插入器,例如 std::inserter 。检查有提示插入是否成功的一种方式是比较插入前后的 size()

重载 (5,6) 通常实现为循环,其中以 end() 为 hint 调用重载 (3) ;它们对后附最小元素大于 *this 中最大元素的有序序列(例如另一 set )优化

示例

    std::set<char> set1;
    std::pair<std::set<char>::iterator, bool> it = set1.insert('A');
    std::cout << "insert 'A' " << (it.second ? "true" : "false") << std::endl;
    it = set1.insert('A');
    std::cout << "insert 'A' " << (it.second ? "true" : "false") << std::endl;

    std::set<char>::const_iterator itb = set1.cbegin();
    std::set<char>::const_iterator itp = set1.insert(itb, 'B');
    std::cout << "insert 'B' : " << *itp << std::endl;

    std::vector<char> arr{'A', 'B', 'C', 'D', 'E'};
    set1.insert(arr.begin(), arr.end());
    printSet("range insert ", set1);

3、emplace (C++11)        原位构造元素        (公开成员函数)

std::set<Key,Compare,Allocator>::emplace
template< class... Args >
std::pair<iterator,bool> emplace( Args&&... args );     (C++11 起) 

若容器中无拥有该关键的元素,则插入以给定的 args 原位构造的新元素到容器。

细心地使用 emplace 允许在构造新元素的同时避免不必要的复制或移动操作。 准确地以与提供给 emplace 者相同的参数,通过 std::forward<Args>(args)... 转发调用新元素的构造函数。 即使容器中已有拥有该关键的元素,也可能构造元素,该情况下新构造的元素将被立即销毁。

没有迭代器或引用被非法化。

参数

args - 要转发给元素构造函数的参数

返回值

返回由指向被插入元素,或若不发生插入则为既存元素的迭代器,和指代插入是否发生的 bool (若发生插入则为 true ,否则为 false )。

异常                    若任何操作抛出异常,则此函数无效果。

复杂度                与容器大小成对数。

示例

    std::set<char> set1;
    char ch = 'A';
    while (ch != 'E')
    {
        set1.emplace(ch);
        ch++;
    }
    printSet("emplace", set1);

4、emplace_hint                  使用提示原位构造元素(公开成员函数)

插入新元素到容器中尽可能接近于恰在 hint 前的位置。原位构造元素,即不进行复制或移动操作。

以提供给函数的参数准确相同者,以 std::forward<Args>(args)... 转发调用元素的构造函数。

没有迭代器或引用被非法化。

参数

hint - 指向新元素将插入到其前的位置的迭代器
args - 转发给元素构造函数的参数

返回值

返回指向新插入元素的迭代器。

若因元素已存在而插入失败,则返回指向拥有等价关键的既存元素的迭代器。

异常

若任何操作抛出异常,则此函数无效果(强异常保证)。

复杂度

通常与容器大小成对数,但若新元素正好被插入到 hint 之前则为均摊常数。

示例

    std::set<char> set1;
    char ch = 'A';
    while (ch != 'C')
    {
        set1.emplace(ch);
        ch++;
    }
    printSet("emplace", set1);

    std::set<char>::const_iterator it = set1.find('B');
    set1.emplace_hint(it, 'D', );
    printSet("emplace_hint", set1);

5、erase         擦除元素(公开成员函数

从容器移除指定的元素。

std::set<Key,Compare,Allocator>::erase

1) 移除位于 pos 的元素。

void erase( iterator pos );                (C++11 前) 

iterator erase( const_iterator pos );      (C++11 起) 

iterator erase( iterator pos );            (C++17 起) 

 2) 移除范围 [first; last) 中的元素,它必须是 *this 中的合法范围。

void erase( iterator first, iterator last );                     (C++11 前) 

iterator erase( const_iterator first, const_iterator last );     (C++11 起) 

 3) 移除关键等于 key 的元素(若存在一个)。

size_type erase( const key_type& key );         (3) 

指向被擦除元素的引用和迭代器被非法化。其他引用和迭代器不受影响。

迭代器 pos 必须合法且可解引用。从而 end() 迭代器(合法,但不可解引用)不能用作 pos 所用的值。

参数

pos - 指向要移除的元素的迭代器
first, last - 要移除的元素范围
key - 要移除的元素关键值

返回值

1-2) 后随最后被移除的元素的迭代器。

3) 被移除的元素数。

异常

1,2) (无)

3) 任何 Compare 对象所抛的异常

复杂度

给定 set 的实例 c

1) 均摊常数

2) log(c.size()) + std::distance(first, last)

3) log(c.size()) + c.count(k)

示例

    std::set<char> set1{'A', 'B', 'C', 'D', 'E'};
    printSet("erase before", set1);
    std::set<char>::const_iterator it = set1.find('C');
    set1.erase(it);
    printSet("erase(it)", set1);
    set1.erase(set1.find('A'), set1.find('D'));
    printSet("erase() range", set1);
    set1.erase('D');
    printSet("erase() value", set1);

6、swap        交换元素(公开成员函数)

将内容与 other 的交换。不在单个元素上调用任何移动、复制或交换操作。

std::set<Key,Compare,Allocator>::swap
void swap( set& other );        (C++17 前) 

void swap( set& other ) noexcept(/* see below */);     (C++17 起) 

将内容与 other 的交换。不在单个元素上调用任何移动、复制或交换操作。

所有迭代器和引用保持合法。尾后迭代器被非法化。

Pred 对象必须可交换 (Swappable) ,并用非成员 swap 的非限定调用交换它们。

std::allocator_traits<allocator_type>::propagate_on_container_swap::value 为 true ,则用非成员 swap 的非限定调用交换分配器。否则,不交换它们(且若 get_allocator() != other.get_allocator() ,则行为未定义)。

(C++11 起)

参数

other - 要与之交换内容的容器

返回值

(无)

异常

任何 Compare 对象交换所抛的异常。

(C++17 前)
noexcept 规定:  

noexcept(std::allocator_traits<Allocator>::is_always_equal::value
&& std::is_nothrow_swappable<Compare>::value)

(C++17 起)

复杂度

常数。

示例

    std::set<char> set1{'A', 'B', 'C'};
    std::set<char> set2{'D', 'E'};
    std::cout << "swap() before" << std::endl;
    printSet("set1", set1);
    printSet("set2", set2);
    set1.swap(set2);
    std::cout << "swap() after" << std::endl;
    printSet("set1", set1);
    printSet("set2", set2);

7、merge 从另一容器接合结点(公开成员函数)

template<class C2>
void merge(std::set<Key, C2, Allocator>& source);         (1) (C++17 起) 

template<class C2>
void merge(std::set<Key, C2, Allocator>&& source);        (2) (C++17 起) 

template<class C2>
void merge(std::multiset<Key, C2, Allocator>& source);    (3) (C++17 起) 

template<class C2>
void merge(std::multiset<Key, C2, Allocator>&& source);   (4) (C++17 起) 

试图释出(“接合”) source 中每个元素,并用 *this 的比较对象插入到 *this 。 若 *this 中有元素,其关键等价于来自 source 中元素的关键,则不从 source 释出该元素。 不复制或移动元素,只会重指向容器结点的内部指针。指向被转移元素的所有指针和引用保持合法,但现在指代到 *this 中而非到 source 中。

若 get_allocator() != source.get_allocator() 则行为未定义。

参数

source - 传递结点来源的兼容容器

返回值

(无)

异常

不抛异常,除非比较抛出。

复杂度

N*log(size()+N)) ,其中 N 为 source.size()

代码汇总

#include <set>
#include <iostream>
#include <ios>
#include <string>
#include <vector>
#include <algorithm>
#include <typeinfo>

// 打印容器元素
template <typename T, typename _Compare = std::less<T>>
void printSet(const std::string &name, const std::set<T, _Compare> &setP)
{
    std::cout << name << " :    ";
    for (auto s : setP)
    {
        std::cout << s << ' ';
    }

    std::cout << std::endl;
}

// 自定义比较
struct myGreaterCompare
{
    myGreaterCompare() {}
    template < typename T>
    bool operator()(const T &a, const T &b)const
    {
        return a > b;
    }
};

void constructor()
{
    std::cout << "constructor start " << std::endl;
    // c++11 初始化容器列表语法:
    // 默认升序
    std::set<char> set1{'A', 'B', 'C', 'D', 'E'};
    printSet("default       ", set1);
    // 递增
    std::set<char, std::less<char>> set2{'A', 'B', 'C', 'D', 'E'};
    printSet("std::less<>   ", set2);
    // 递减
    std::set<char, std::greater<char>> set3{'A', 'B', 'C', 'D', 'E'};
    printSet("std::greater<>", set3);
    // 自定义比较函数
    std::set<char, myGreaterCompare> set4{'A', 'B', 'C', 'D', 'E'};
    printSet("myGreaterCompare", set4);

    // 拷贝构造函数, set<T> 必须同类型,包括比较
    std::set<char, std::greater<char>> set5(set3);
    printSet("copy constructor", set5);

    // 赋值构造函数, set<T> 必须同类型,包括比较
    std::set<char, std::less<char>> set6 = set2;
    printSet("assignment constructor", set6);

    // 范围构造
    std::set<char, myGreaterCompare> set7(set6.begin(), set6.end());
    printSet("range constructor", set7);
    std::cout << "constructor end " << std::endl << std::endl;
}

void capacity()
{
    std::cout << "capacity start " << std::endl;

    // 检查容器是否无元素
    std::set<char> set1;
    std::cout << "set1 is empty ? :   " << (set1.empty() ? "empty" : "no empty") << std::endl;
    set1.insert('A');
    std::cout << "set1 is empty ? :   " << (set1.empty() ? "empty" : "no empty") << std::endl;

    // 返回容器中的元素数
    std::set<char> set2;
    std::cout << "set2 size : " << set2.size() << std::endl;
    set2 = std::set<char> {'A', 'B', 'C', 'D', 'E'};
    std::cout << "set2 size : " << set2.size() << std::endl;

    // 返回根据系统或库实现限制的容器可保有的元素最大数量
    std::set<char> set3;
    std::cout << "std::set<char> max_size() : " << set3.max_size() << std::endl;
    std::set<int> set4;
    std::cout << "std::set<int> max_size() : " << set4.max_size() << std::endl;
    std::set<std::string> set5;
    std::cout << "std::set<std::string> max_size() : " << set5.max_size() << std::endl;
    std::set<double> set6;
    std::cout << "std::set<double> max_size() : " << set6.max_size() << std::endl;
    std::cout << "capacity end " << std::endl << std::endl;
}

void compareFunc()
{
    // 返回比较值的函数对象
    std::cout << "observer start " << std::endl;
    std::set<char> set1;
    std::cout << "std::set<char> key_comp() : "
              << typeid(set1.key_comp()).name() << std::endl;
    // 比较'A','B'大小,'A'比'B'小
    std::cout << "std::less<> compare('A','B') :  " <<
              (set1.key_comp()('A', 'B') ? "true" : "false") << std::endl;

    std::set<char, std::greater<char>> set2;
    std::cout << "std::set<char, std::greater<char>> key_comp() : "
              << typeid(set2.key_comp()).name() << std::endl;
    // 比较'A','B'大小,'A'比'B'大
    std::cout << "std::greater<> compare('A','B') :  " <<
              (set1.key_comp()('A', 'B') ? "true" : "false") << std::endl;

    std::set<char, myGreaterCompare> set3;
    std::cout << "std::set<char, myGreaterCompare> key_comp() : "
              << typeid(set3.key_comp()).name() << std::endl;

    std::cout << "observer end " << std::endl << std::endl;
}

void clearTest()
{
    std::cout << "clearTest start " << std::endl;
    std::set<char> set1{'A', 'B', 'C', 'D', 'E'};
    std::cout << "set1 size: " << set1.size() << std::endl;
    set1.clear();
    std::cout << "clear after set1 size: " << set1.size() << std::endl;
    std::cout << "clearTest end " << std::endl << std::endl;
}

void insertTest()
{
    std::cout << "insertTest start " << std::endl;
    std::set<char> set1;
    std::pair<std::set<char>::iterator, bool> it = set1.insert('A');
    std::cout << "insert 'A' " << (it.second ? "true" : "false") << std::endl;
    it = set1.insert('A');
    std::cout << "insert 'A' " << (it.second ? "true" : "false") << std::endl;

    std::set<char>::const_iterator itb = set1.cbegin();
    std::set<char>::const_iterator itp = set1.insert(itb, 'B');
    std::cout << "insert 'B' : " << *itp << std::endl;

    std::vector<char> arr{'A', 'B', 'C', 'D', 'E'};
    set1.insert(arr.begin(), arr.end());
    printSet("range insert ", set1);

    std::cout << "insertTest end " << std::endl << std::endl;
}

void emplaceTest()
{
    std::cout << "emplaceTest start " << std::endl;
    std::set<char> set1;
    char ch = 'A';
    while (ch != 'C')
    {
        set1.emplace(ch);
        ch++;
    }
    printSet("emplace", set1);

    std::set<char>::const_iterator it = set1.find('B');
    set1.emplace_hint(it, 'D');
    printSet("emplace_hint", set1);

    std::cout << "emplaceTest end " << std::endl << std::endl;
}

void eraseTest()
{
    std::cout << "eraseTest start " << std::endl;
    std::set<char> set1{'A', 'B', 'C', 'D', 'E'};
    printSet("erase before", set1);
    std::set<char>::const_iterator it = set1.find('C');
    set1.erase(it);
    printSet("erase(it)", set1);
    set1.erase(set1.find('A'), set1.find('D'));
    printSet("erase() range", set1);
    set1.erase('D');
    printSet("erase() value", set1);
    std::cout << "eraseTest end " << std::endl << std::endl;
}

void swapTest()
{
    std::cout << "swapTest start " << std::endl;
    std::set<char> set1{'A', 'B', 'C'};
    std::set<char> set2{'D', 'E'};
    std::cout << "swap() before" << std::endl;
    printSet("set1", set1);
    printSet("set2", set2);
    set1.swap(set2);
    std::cout << "swap() after" << std::endl;
    printSet("set1", set1);
    printSet("set2", set2);
    std::cout << "swapTest end " << std::endl << std::endl;
}

int main()
{
//    constructor();
//    capacity();
//    compareFunc();
    clearTest();
    insertTest();
    emplaceTest();
    eraseTest();
    swapTest();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40788199/article/details/121728380