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;
}
目录
相关文章
|
4月前
|
算法 C++ 容器
C++标准库(速查)总结
C++标准库(速查)总结
110 6
|
24天前
|
C++ 容器
【c++丨STL】stack和queue的使用及模拟实现
本文介绍了STL中的两个重要容器适配器:栈(stack)和队列(queue)。容器适配器是在已有容器基础上添加新特性或功能的结构,如栈基于顺序表或链表限制操作实现。文章详细讲解了stack和queue的主要成员函数(empty、size、top/front/back、push/pop、swap),并提供了使用示例和模拟实现代码。通过这些内容,读者可以更好地理解这两种数据结构的工作原理及其实现方法。最后,作者鼓励读者点赞支持。 总结:本文深入浅出地讲解了STL中stack和queue的使用方法及其模拟实现,帮助读者掌握这两种容器适配器的特性和应用场景。
55 21
|
1月前
|
XML 网络协议 API
超级好用的C++实用库之服务包装类
通过本文对Boost.Asio、gRPC和Poco三个超级好用的C++服务包装类库的详细介绍,开发者可以根据自己的需求选择合适的库来简化开发工作,提高代码的效率和可维护性。每个库都有其独特的优势和适用场景,合理使用这些库可以极大地提升C++开发的生产力。
47 11
|
2月前
|
编译器 C语言 C++
【c++丨STL】list模拟实现(附源码)
本文介绍了如何模拟实现C++中的`list`容器。`list`底层采用双向带头循环链表结构,相较于`vector`和`string`更为复杂。文章首先回顾了`list`的基本结构和常用接口,然后详细讲解了节点、迭代器及容器的实现过程。 最终,通过这些步骤,我们成功模拟实现了`list`容器的功能。文章最后提供了完整的代码实现,并简要总结了实现过程中的关键点。 如果你对双向链表或`list`的底层实现感兴趣,建议先掌握相关基础知识后再阅读本文,以便更好地理解内容。
42 1
|
2月前
|
算法 C语言 C++
【c++丨STL】list的使用
本文介绍了STL容器`list`的使用方法及其主要功能。`list`是一种双向链表结构,适用于频繁的插入和删除操作。文章详细讲解了`list`的构造函数、析构函数、赋值重载、迭代器、容量接口、元素访问接口、增删查改操作以及一些特有的操作接口如`splice`、`remove_if`、`unique`、`merge`、`sort`和`reverse`。通过示例代码,读者可以更好地理解如何使用这些接口。最后,作者总结了`list`的特点和适用场景,并预告了后续关于`list`模拟实现的文章。
69 7
|
3月前
|
存储 编译器 C语言
【c++丨STL】vector的使用
本文介绍了C++ STL中的`vector`容器,包括其基本概念、主要接口及其使用方法。`vector`是一种动态数组,能够根据需要自动调整大小,提供了丰富的操作接口,如增删查改等。文章详细解释了`vector`的构造函数、赋值运算符、容量接口、迭代器接口、元素访问接口以及一些常用的增删操作函数。最后,还展示了如何使用`vector`创建字符串数组,体现了`vector`在实际编程中的灵活性和实用性。
135 4
|
3月前
|
C语言 C++ 容器
【c++丨STL】string模拟实现(附源码)
本文详细介绍了如何模拟实现C++ STL中的`string`类,包括其构造函数、拷贝构造、赋值重载、析构函数等基本功能,以及字符串的插入、删除、查找、比较等操作。文章还展示了如何实现输入输出流操作符,使自定义的`string`类能够方便地与`cin`和`cout`配合使用。通过这些实现,读者不仅能加深对`string`类的理解,还能提升对C++编程技巧的掌握。
140 5
|
3月前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
89 2
|
3月前
|
存储 算法 Linux
【c++】STL简介
本文介绍了C++标准模板库(STL)的基本概念、组成部分及学习方法,强调了STL在提高编程效率和代码复用性方面的重要性。文章详细解析了STL的六大组件:容器、算法、迭代器、仿函数、配接器和空间配置器,并提出了学习STL的三个层次,旨在帮助读者深入理解和掌握STL。
100 0
|
2月前
|
存储 编译器 C语言
【c++丨STL】vector模拟实现
本文深入探讨了 `vector` 的底层实现原理,并尝试模拟实现其结构及常用接口。首先介绍了 `vector` 的底层是动态顺序表,使用三个迭代器(指针)来维护数组,分别为 `start`、`finish` 和 `end_of_storage`。接着详细讲解了如何实现 `vector` 的各种构造函数、析构函数、容量接口、迭代器接口、插入和删除操作等。最后提供了完整的模拟实现代码,帮助读者更好地理解和掌握 `vector` 的实现细节。
67 0