C++ STL库的介绍和使用(下)

简介: C++ STL库的介绍和使用

C++ STL库的介绍和使用(上):https://developer.aliyun.com/article/1459450


set/multiset


set的特性是:所有元素都会根据元素的键值自动排序。set元素不像map那样可以同时拥有键和值,set元素既是键又是值。set不允许两个元素拥有同样的键值。


set不可以通过迭代器修改set的值,set的值也是键,关系到set元素的排序规则。


multiset的特性和用法和set完全相同,唯一不同的是multiset允许键值重复。set和multiset的底层实现是红黑树,红黑书是平衡二叉树的一种。

#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
void print(const set<int> &ll)
{
    for(auto & a : ll)
    {
        cout << a << " ";
    }
    cout << endl;
    fflush(stdout);
}
class Compare
{
public:
    bool operator()(const int& p1,const int& p2) const//一定要定义为常函数,且参数需要限定为const
    {
        return p1 > p2;
    }
};
void print(const set<int, Compare> &ll)
{
    for(auto & a : ll)
    {
        cout << a << " ";
    }
    cout << endl;
    fflush(stdout);
}
void test()
{
    set<int> ss;
    ss.insert(2);
    ss.insert(3);
    ss.insert(45);
    ss.insert(10);
    ss.insert(2);
    print(ss);
    cout << ss.size() << endl;
    ss.erase(3);
    print(ss);
    cout << ss.count(2) << endl;
    multiset<int> ss2;
    ss2.insert(2);
    ss2.insert(3);
    ss2.insert(45);
    ss2.insert(10);
    ss2.insert(2);
    ss2.erase(3);
    cout << ss2.count(2) << endl;
    auto it = ss.find(5);
    it != ss.end()? cout << "找到了" << endl : cout << "没有找到" << endl;
    auto it1 = lower_bound(ss.begin(), ss.end(), 10);
    auto it2 = upper_bound(ss.begin(), ss.end(), 10);
    auto mm = ss.equal_range(30);
}
void test01()
{
    set<int, Compare> ss;
    ss.insert(2);
    ss.insert(6);
    ss.insert(8);
    print(ss);
}
int main(int argc, char* argv[])
{
    test01();
    return 0;
}

注意: set存放自定义数据类型的时候必须指定排序规则。


pair


对组是将一对值组合成一个值,这一对值可以具有不同的数据类型,两个值可以分别用pair的两个公有属性first和second进行访问。

#include <iostream>
#include <algorithm>
using namespace std;
void test()
{
    pair<int, int> pp(1, 2);
    cout << pp.first << " " << pp.second << endl;
    pair<int, int> pp1 = make_pair(1, 2);
    cout << pp1.first << " " << pp1.second << endl;
}
int main(int argc, char* argv[])
{
    test();
    return 0;
}


map/multimap


map的特性是所有元素会根据元素的键值自动排序。map所有的元素都是pair,同时拥有实值和键值,pair的第一个元素是键值,第二个元素被视为实值,map不允许两个元素有相同的键值。

map的键值不可变,实值是可变的。


multimap和map的操作类似,唯一的区别就是multimap键值可重复。map和multimap都是以红黑树为底层实现机制。

#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
void print(const map<int, int> &ll)
{
    for(auto & a : ll)
    {
        cout << a.first << " " << a.second << " " << endl;
    }
    fflush(stdout);
}
void test()
{
    int a = 10;
    int &b = a;
    a = 20;
    cout << a << endl;
    cout << b << endl;
}
int main(int argc, char* argv[])
{
    test();
    return 0;
}


容器的使用时机


典型的存储结构 可随机存取
vector 单端数组
deque 双端数组
list 双向列表
set/multiset 红黑树
map/multimap 红黑树 否(针对于ke)


元素查询 元素插入删除
vector 尾部
deque 两端
list 非常慢 任何位置
set/multiset
map/multimap


函数对象(仿函数)


重载函数调用操作符的对象,其对象常称为函数对象,即他们是行为类似于函数的对象,也叫仿函数,其实就是重载了"()"操作符,使得对象可以像函数那样调用。


注意:

  • 函数对象是一个类,不是一个函数。
  • 函数对象重载了"()"操作符,使他可以像函数一样调用。


分类:

  • 如果一个函数重载了"()"且需要一个参数,则称为一元仿函数
  • 如果一个函数重载了"()"且需要两个参数,则称为二元仿函数


总结:

  • 函数对象通常不定义构造函数和析构函数,所以在构造和析构的时候不会发生任何问题,避免了函数调用的运行时问题。
  • 函数对象超出了普通函数的概念,函数对象可以有自己的状态
  • 函数对象可以内联编译,性能好。用函数指针几乎不可能
  • 模板函数对象使得函数对象具有通用性,这就是他的优势之一


谓词


指的是普通函数或者是仿函数的返回值是bool类型的函数对象。

如果operator接受一个参数,则叫一元谓词,如果接受2个参数则称为二元谓词。

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
bool findBigThan10(int a)
{
    return a > 10;
}
class Find20
{
public:
    bool operator()(int v)
    {
        return v > 20;
    }
};
void test()
{
    vector<int> vv;
    vv.push_back(10);
    vv.push_back(20);
    vv.push_back(30);
    vv.push_back(40);
    vv.push_back(50);
    vv.push_back(60);
    auto ret = find_if(vv.begin(), vv.end(), findBigThan10);
    auto ret1 = find_if(vv.begin(), vv.end(), Find20());
    cout << *ret << endl;
    cout << *ret1 << endl;
}
bool compare(int left, int right)
{
    return left > right;
}
class Compare
{
public:
    bool operator()(int left, int right)
    {
        return left < right;
    }
};
void test02()
{
    vector<int> vv;
    vv.push_back(10);
    vv.push_back(20);
    vv.push_back(30);
    vv.push_back(40);
    vv.push_back(50);
    vv.push_back(60);
    sort(vv.begin(), vv.end(), compare);
    for_each(vv.begin(), vv.end(), [](int val){
        cout << val << " ";
    });
    cout << endl;
    sort(vv.begin(), vv.end(), Compare());
    for_each(vv.begin(), vv.end(), [](int val){
        cout << val << " ";
    });
    cout << endl;
}
int main(int argc, char* argv[])
{
    test02();
    return 0;
}


内建函数对象


STL内建了一些函数对象,分为:算数类函数对象,关系运算类函数对象,逻辑运算类仿函数。这些仿函数所产生的对象,用法和一般函数完全相同,当然我们还可以产生无名的临时对象来履行函数功能。

下面列出一些简单的例子。如果想要查看内建的函数,可以到对应的文件内查看对应的函数原型。

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
bool findBigThan10(int a)
{
    return a > 10;
}
class Find20
{
public:
    bool operator()(int v)
    {
        return v > 20;
    }
};
void test()
{
    plus<int> p;
    cout << p(10, 20) << endl;
    cout << plus<int>()(50, 20) << endl;
    minus<int> p1;
    cout << p1(10, 20) << endl;
}
int main(int argc, char* argv[])
{
    test();
    return 0;
}


适配器


bind2nd和bind1st

#define _HAS_AUTO_PTR_ETC 1
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
void print(int a, int b)
{
    cout << a << " " << b << " " << endl;
}
class Print : public binary_function<int, int, void>
{
public:
    void operator()(int a, int b) const
    {
        cout << a << " " << b << " " << endl;
    }
};
void test()
{
    vector<int> vv;
    vv.push_back(10);
    vv.push_back(20);
    vv.push_back(30);
    vv.push_back(40);
    for_each(vv.begin(), vv.end(), bind1st(Print(), 5));
    for_each(vv.begin(), vv.end(), bind2nd(Print(), 5));
}
int main(int argc, char* argv[])
{
    test();
    return 0;
}


not1 和 not2 mem_fun_ref和ptr_fun


这里列出标题,不做代码展示


算法


算法主要是由头文件组成,是所有stl头文件中最大的一个,其中常用的功能涉及到比较,交换,查找,遍历,修改,翻转,排序,合并等。体积很小,只包括在几个序列容器上进行的简单运算的模板函数,定义了一些模板类,用以声明函数对象。


常用的遍历算法


  • for_each
  • transform
#define _HAS_AUTO_PTR_ETC 1
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
int mvTransform(int a)
{
    return a;
}
class Print : public binary_function<int, int, void>
{
public:
    void operator()(int a, int b) const
    {
        cout << a << " " << b << " " << endl;
    }
};
void test()
{
    vector<int> vv;
    vv.push_back(10);
    vv.push_back(20);
    vv.push_back(30);
    vv.push_back(40);
    vector<int> bb;
    bb.resize(vv.size());
    transform(vv.begin(), vv.end(), bb.begin(), mvTransform);
    for_each(bb.begin(), bb.end(), bind2nd(Print(), 5));
}
int main(int argc, char* argv[])
{
    test();
    return 0;
}


常用的查找算法


  • find
  • find_if
  • adjacent_find 查找相邻的重复元素
  • binary_find 二分查找,前提是容器必须有序
  • count 统计元素出现次数
  • count_if 按照条件统计次数
#define _HAS_AUTO_PTR_ETC 1
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
class Person
{
public:
    Person(int a) : age(a) {}
    int age;
};
bool operator==(const Person &left, const Person &right)
{
    return left.age == right.age;
}
void test()
{
    vector<int> vv;
    vv.push_back(10);
    vv.push_back(10);
    vv.push_back(20);
    vv.push_back(30);
    vv.push_back(30);
    auto it = adjacent_find(vv.begin(), vv.end());
    if(it != vv.end())
    {
        cout << *it << endl;
    }
    vector<Person> vp;
    vp.push_back(50);
    vp.push_back(50);
    auto itP = adjacent_find(vp.begin(), vp.end());
    if(itP != vp.end())
    {
        cout << itP->age << endl;
    }

}
int main(int argc, char* argv[])
{
    test();
    return 0;
}


其他


  • merge
  • sort
  • random_shuffle 打乱
  • reverse 反转
  • copy
  • replace
  • replace_if
  • swap 交换函数
#define _HAS_AUTO_PTR_ETC 1
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
void test()
{
    vector<int> vv;
    vv.push_back(10);
    vv.push_back(10);
    vv.push_back(20);
    vv.push_back(20);
    vv.push_back(30);
    vv.push_back(30);
    vv.push_back(40);
    vv.push_back(40);
    vector<int> v2;
    v2.push_back(10);
    v2.push_back(30);
    vector<int> v3;
    v3.resize(vv.size() + v2.size());
    merge(vv.begin(), vv.end(), v2.begin(), v2.end(), v3.begin());
    for_each(v3.begin(), v3.end(), [](int a){
        cout << a << " ";
    });
}
int main(int argc, char* argv[])
{
    test();
    return 0;
}


算数生成算法


  • accumulate 累加求和
  • fill
#define _HAS_AUTO_PTR_ETC 1
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <numeric>
using namespace std;
void test()
{
    vector<int> vv;
    vv.push_back(10);
    vv.push_back(10);
    int sum = accumulate(vv.begin(), vv.end(), 0);
    cout << sum << endl;
    fill(vv.begin(), vv.end(), 20);
    for_each(vv.begin(), vv.end(), [](int a){ cout << a << endl; });
}
int main(int argc, char* argv[])
{
    test();
    return 0;
}


集合算法


  • set_intersection 求交集
#define _HAS_AUTO_PTR_ETC 1
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <numeric>
using namespace std;
void test()
{
    vector<int> vv;
    vv.push_back(10);
    vv.push_back(20);
    vv.push_back(30);
    vv.push_back(40);
    vector<int> v2;
    v2.push_back(30);
    v2.push_back(40);
    v2.push_back(50);
    v2.push_back(60);
    vector<int> v3;
    v3.resize(4);
    auto it = set_intersection(vv.begin(), vv.end(), v2.begin(), v2.end(), v3.begin());
    int size = 4 - (v3.end() - it);
    v3.resize(size);
    for_each(v3.begin(), v3.end(), [](int a){ cout << a << endl;});
}
int main(int argc, char* argv[])
{
    test();
    return 0;
}


  • set_union 求交集
#define _HAS_AUTO_PTR_ETC 1
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <numeric>
using namespace std;
void test()
{
    vector<int> vv;
    vv.push_back(10);
    vv.push_back(20);
    vv.push_back(30);
    vv.push_back(40);
    vector<int> v2;
    v2.push_back(30);
    v2.push_back(40);
    v2.push_back(50);
    v2.push_back(60);
    vector<int> v3;
    v3.resize(8);
    auto it = set_union(vv.begin(), vv.end(), v2.begin(), v2.end(), v3.begin());
    int size = 8 -(v3.end() - it);
    v3.resize(size);
    for_each(v3.begin(), v3.end(), [](int a){ cout << a << endl;});
}
int main(int argc, char* argv[])
{
    test();
    return 0;
}


  • set_difference 求差集
#define _HAS_AUTO_PTR_ETC 1
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <numeric>
using namespace std;
void test()
{
    vector<int> vv;
    vv.push_back(10);
    vv.push_back(20);
    vv.push_back(30);
    vv.push_back(40);
    vector<int> v2;
    v2.push_back(30);
    v2.push_back(40);
    v2.push_back(50);
    v2.push_back(60);
    vector<int> v3;
    v3.resize(4);
    auto it = set_difference(vv.begin(), vv.end(), v2.begin(), v2.end(), v3.begin());
    int size = 4 -(v3.end() - it);
    v3.resize(size);
    for_each(v3.begin(), v3.end(), [](int a){ cout << a << endl;});
}
int main(int argc, char* argv[])
{
    test();
    return 0;
}
目录
相关文章
|
1月前
|
算法 C++ 容器
C++标准库(速查)总结
C++标准库(速查)总结
61 6
|
1月前
|
存储 算法 C++
C++ STL 初探:打开标准模板库的大门
C++ STL 初探:打开标准模板库的大门
94 10
|
1月前
|
存储 搜索推荐 C++
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
48 2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
|
1月前
|
存储 程序员 C++
C++常用基础知识—STL库(2)
C++常用基础知识—STL库(2)
69 5
|
1月前
|
存储 自然语言处理 程序员
C++常用基础知识—STL库(1)
C++常用基础知识—STL库(1)
52 1
|
1月前
|
算法 安全 Linux
【C++STL简介】——我与C++的不解之缘(八)
【C++STL简介】——我与C++的不解之缘(八)
|
1月前
|
存储 C++ 容器
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器1
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
52 5
|
1月前
|
存储 编译器 C++
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
53 2
|
1月前
|
算法 数据处理 C++
c++ STL划分算法;partition()、partition_copy()、stable_partition()、partition_point()详解
这些算法是C++ STL中处理和组织数据的强大工具,能够高效地实现复杂的数据处理逻辑。理解它们的差异和应用场景,将有助于编写更加高效和清晰的C++代码。
22 0
|
7天前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
33 4