C++的STL都由什么组成

C++标准模板库(STL)是C++语言的一部分,提供了一系列模板类和函数,旨在帮助程序员处理常见的编程任务,如数据结构和算法操作。
STL主要包括四大组件:
容器(Containers)、
迭代器(Iterators)、
算法(Algorithms)
函数对象(Function objects)。
下面是对这些组件的详细介绍:

1. 容器(Containers)

容器是用来管理某一类对象的集合。STL提供了多种不同类型的容器,每种容器都设计用来管理特定类型的对象集合。

  • 序列容器(Sequence Containers):管理元素的线性排列。

    • vector:动态数组,支持快速随机访问,也就是人家大小是可以动态改变的!这点和静态数组有区别!
    • list:双向链表,支持快速插入和删除。
    • deque:双端队列,两端都可以快速插入和删除。
    • forward_list(C++11):单向链表,效率高于list但只能单向遍历。
    • array(C++11):固定大小数组,支持快速随机访问,大小在编译时确定。
  • 关联容器(Associative Containers):基于键来管理元素的集合。

    • set:元素唯一且自动排序的集合。
    • multiset:元素可以重复且自动排序的集合。
    • map:基于键值对的集合,键唯一且自动排序。
    • multimap:基于键值对的集合,键可以重复且自动排序。
  • 无序关联容器(Unordered Associative Containers)(C++11):基于哈希表的容器,元素不自动排序。

    • unordered_set:元素唯一的集合。
    • unordered_multiset:元素可以重复的集合。
    • unordered_map:基于键值对的集合,键唯一。
    • unordered_multimap:基于键值对的集合,键可以重复。

2. 迭代器(Iterators)

迭代器提供了一种访问容器元素的方法,而不需要了解容器的内部工作原理。它类似于指针,可以用来遍历STL容器中的元素。

  • 迭代器类型
    • 输入迭代器
    • 输出迭代器
    • 前向迭代器
    • 双向迭代器
    • 随机访问迭代器

3. 算法(Algorithms)

STL提供了一系列标准算法,如排序、搜索、修改序列等操作,这些算法通常通过迭代器与容器进行交互。

  • 算法类型
    • 非修改序列算法
    • 修改序列算法
    • 排序和相关操作
    • 通用数值算法

4. 函数对象(Function objects)

函数对象(也称为仿函数)是实现了operator()的类的实例。STL中的函数对象可以用作算法的比较函数、执行特定操作的函数等。

  • 函数对象的分类
    • 算术运算类
    • 关系运算类
    • 逻辑运算类
    • 自定义仿函数

5. 适配器(Adapters)

适配器是一种特殊的容器、迭代器或函数对象,它通过特定的接口对STL提供的其他组件进行封装,以改变其行为。

  • 容器适配器stackqueuepriority_queue
  • 迭代器适配器reverse_iteratorinsert_iteratorstream_iterator
  • 函数适配器bind function(C++11)
    STL是C++中非常强大的一部分,掌握它可以极大地提高编程效率和代码质量。通过结合使用不同的STL组件,可以解决大多数编程问题,并写出既简洁又高效的代码。

一些代码示例
让我们通过具体的代码示例来探讨C++标准模板库(STL)的各个组件及其语法,以及它们解决的问题。

1. 容器(Containers)

vector(动态数组)
#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    vec.push_back(6); // 在末尾添加一个元素
    std::cout << "Vector: ";
    for(int num : vec) {
        std::cout << num << " ";
    }
    std::cout << "\n";
}

问题解决std::vector提供了一个动态大小的数组。与普通数组相比,它可以在运行时动态地改变大小,非常适合于不知道确切元素数量的情况。

2. 迭代器(Iterators)

使用迭代器遍历vector
#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    for(auto it = vec.begin(); it != vec.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << "\n";
}

问题解决:迭代器提供了一种统一的方式来访问容器中的元素,不需要关心容器的具体类型。

3. 算法(Algorithms)

sort(排序)
#include <algorithm>
#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec = {5, 3, 4, 1, 2};
    std::sort(vec.begin(), vec.end());
    for(int num : vec) {
        std::cout << num << " ";
    }
    std::cout << "\n";
}

问题解决:STL中的算法如std::sort,提供了通用的解决方案,用于执行如排序、搜索等常见操作,而无需手动实现。

4. 函数对象(Function objects)

使用函数对象进行比较
#include <algorithm>
#include <vector>
#include <iostream>

struct greater {
    bool operator()(int a, int b) {
        return a > b;
    }
};

int main() {
    std::vector<int> vec = {5, 3, 4, 1, 2};
    std::sort(vec.begin(), vec.end(), greater());
    for(int num : vec) {
        std::cout << num << " ";
    }
    std::cout << "\n";
}

问题解决:函数对象允许将行为(如比较)封装在对象中,这使得算法如std::sort能够以通用和灵活的方式执行。

5. 适配器(Adapters)

stack(栈)
#include <stack>
#include <iostream>

int main() {
    std::stack<int> stk;
    stk.push(1);
    stk.push(2);
    stk.push(3);

    while(!stk.empty()) {
        std::cout << stk.top() << " ";
        stk.pop();
    }
    std::cout << "\n";
}

问题解决:容器适配器如std::stack提供了特定的数据结构的接口,例如栈(LIFO顺序)。它们使得对这些数据结构的操作更为直观和简洁。

通过这些示例,我们可以看到STL如何提供了一套丰富的工具和抽象,让处理数据结构和算法更加简单和高效。STL的设计允许程序员以通用的方式编写代码,从而提高了代码的复用性和可维护性。

函数对象更加具体的用法

函数对象(也称为仿函数)是一种使用对象模拟函数调用的技术。它们通过重载operator()实现,这让对象可以像函数一样被调用。虽然在日常编程中可能不如普通函数或Lambda表达式那样频繁见到,但函数对象在某些情况下非常有用,特别是在需要对象保持状态或需要多次重用操作逻辑时。下面是一些函数对象的其他示例和使用场景:

1. 带状态的函数对象

函数对象可以携带状态(即类成员变量的值),这允许它在多次调用之间保持某些信息。

#include <iostream>
#include <vector>
#include <algorithm>

class CountIf {
private:
    int threshold;
public:
    CountIf(int t) : threshold(t) {}
    bool operator()(int x) {
        return x > threshold;
    }
};

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    CountIf countIf5(5); // 创建一个阈值为5的函数对象
    int count = std::count_if(vec.begin(), vec.end(), countIf5);
    std::cout << "There are " << count << " numbers greater than 5\n";
}

这个例子中,CountIf函数对象根据构造时给定的阈值来判断整数是否满足条件,并在使用std::count_if算法时携带状态(阈值)。

2. 结合STL算法使用函数对象

函数对象可以与STL算法结合使用,提供自定义的比较逻辑或操作。

#include <iostream>
#include <algorithm>
#include <vector>

class Multiply {
public:
    int operator()(int x) {
        return x * 2;
    }
};

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    std::transform(vec.begin(), vec.end(), vec.begin(), Multiply());
    
    for(int num : vec) {
        std::cout << num << " ";
    }
    std::cout << "\n";
}

在这个例子中,Multiply函数对象被用于std::transform算法中,将向量中的每个元素乘以2。

3. 作为比较函数的函数对象

在需要自定义排序准则时,函数对象可以用作比较函数。

#include <iostream>
#include <algorithm>
#include <vector>

class Descend {
public:
    bool operator()(int a, int b) {
        return a > b; // 降序排列
    }
};

int main() {
    std::vector<int> vec = {5, 3, 1, 4, 2};
    std::sort(vec.begin(), vec.end(), Descend());
    
    for(int num : vec) {
        std::cout << num << " ";
    }
    std::cout << "\n";
}

这里,Descend函数对象用于std::sort,实现了一个降序排序。

总结

函数对象提供了一种灵活的方式来封装操作逻辑,可以携带状态,可以重复使用,并且可以被STL算法等接受作为参数的地方使用。通过使用函数对象,可以在C++中实现更复杂和强大的功能。

  • 19
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值