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;
}
目录
相关文章
|
19小时前
|
算法 编译器 C语言
从C语言到C++⑩(第四章_模板初阶+STL简介)如何学习STL(下)
从C语言到C++⑩(第四章_模板初阶+STL简介)如何学习STL
4 0
|
4天前
|
存储 算法 搜索推荐
C++|STL简介-string-vector基础运用
C++|STL简介-string-vector基础运用
|
6天前
|
Linux Shell 开发工具
C++ 的 ini 配置文件读写/注释库 inicpp 用法 [ header-file-only ]
这是一个C++库,名为inicpp,用于读写带有注释的INI配置文件,仅包含一个hpp头文件,无需编译,支持C++11及以上版本。该库提供简单的接口,使得操作INI文件变得容易。用户可通过`git clone`从GitHub或Gitee获取库,并通过包含`inicpp.hpp`来使用`inicpp::iniReader`类。示例代码展示了读取、写入配置项以及添加注释的功能,还提供了转换为字符串、双精度和整型的函数。项目遵循MIT许可证,示例代码可在Linux环境下编译运行。
37 0
|
6天前
|
设计模式 算法 C++
【C++】STL之迭代器介绍、原理、失效
【C++】STL之迭代器介绍、原理、失效
13 2
|
6天前
|
机器学习/深度学习 JSON 编译器
C++ 资源大全:标准库、Web框架、人工智能等 | 最全整理
C++ 资源列表,内容包括: 标准库、Web应用框架、人工智能、数据库、图片处理、机器学习、日志、代码分析等
52 1
|
6天前
|
存储 C++ 容器
C++:STL - set & map
C++:STL - set & map
16 4
|
6天前
|
算法 安全 程序员
【C++】STL学习之旅——初识STL,认识string类
现在我正式开始学习STL,这让我期待好久了,一想到不用手撕链表,手搓堆栈,心里非常爽
17 0
|
6天前
|
JSON Java Linux
【探索Linux】P.30(序列化和反序列化 | JSON序列化库 [ C++ ] )
【探索Linux】P.30(序列化和反序列化 | JSON序列化库 [ C++ ] )
23 2
|
6天前
|
存储 安全 算法
【C++入门到精通】 原子性操作库(atomic) C++11 [ C++入门 ]
【C++入门到精通】 原子性操作库(atomic) C++11 [ C++入门 ]
16 1
|
6天前
|
算法 安全 调度
【C++入门到精通】 线程库 | thread类 C++11 [ C++入门 ]
【C++入门到精通】 线程库 | thread类 C++11 [ C++入门 ]
17 1