C++标准模板库(STL)容器、算法、迭代器

一. STL(标准模板库)的概述

定义:STL(Standard Template Library)是C++标准库的一部分,它提供了一系列通用的模板类和函数,用于处理常见的编程任务,如数据存储、排序、搜索等,旨在提高代码的复用性和效率。

组成部分:STL主要由容器(Containers)、算法(Algorithms)和迭代器(Iterators)三大组件构成,此外还包括函数对象(Function objects)、适配器(Adapters)和分配器(Allocators)等辅助组件。

二. 容器(Containers)

1. 顺序容器 vector:

vector是一个动态大小的数组,可以在末尾快速插入和删除元素。它在内存中是连续存储的,这使得随机访问元素非常高效(时间复杂度为$O(1)$),但在中间插入或删除元素可能会比较慢(平均时间复杂度为$O(n)$,其中$n$是容器中的元素个数)。

#include <vector>
#include <iostream>
int main() {
    std::vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    for (size_t i = 0; i < v.size(); i++) {
        std::cout << v[i] << " ";
    }
    return 0;
}

2. 顺序容器 list:

list是一个双向链表,它的每个节点包含一个元素和指向前一个节点和后一个节点的指针。在list中任意位置插入和删除元素都非常快(时间复杂度为$O(1)$),但随机访问元素比较慢(时间复杂度为$O(n)$)。

#include <list>
#include <iostream>
int main() {
    std::list<int> l;
    l.push_back(1);
    l.push_back(2);
    l.push_back(3);
    for (auto it = l.begin(); it!= l.end(); ++it) {
        std::cout << *it << " ";
    }
    return 0;
}

3. 顺序容器 deque(双端队列):

deque(发音为“deck”)是一种双端队列,它类似于vector,但在两端插入和删除元素都非常高效(时间复杂度为$O(1)$)。deque内部的存储结构可能不是连续的,而是由多个固定大小的块组成。

#include <deque>
#include <iostream>
int main() {
    std::deque<int> d;
    d.push_back(1);
    d.push_front(0);
    for (size_t i = 0; i < d.size(); i++) {
        std::cout << d[i] << " ";
    }
    return 0;
}

4. 关联容器 set:

set是一个有序的集合,其中的元素是唯一的。它基于红黑树实现,插入、删除和查找操作的时间复杂度都是$O(\log n)$。set会自动对元素进行排序。

#include <set>
#include <iostream>
int main() {
    std::set<int> s;
    s.insert(3);
    s.insert(1);
    s.insert(2);
    for (auto it = s.begin(); it!= s.end(); ++it) {
        std::cout << *it << " ";
    }
    return 0;
}

5. 关联容器 map:

map是一个键 - 值对的有序集合,每个键在map中是唯一的。它基于红黑树实现,插入、删除和查找操作的时间复杂度都是$O(\log n)$。可以通过键快速查找对应的值。

#include <map>
#include <iostream>
int main() {
    std::map<int, int> m;
    m.insert(std::make_pair(1, 10));
    m.insert(std::make_pair(2, 20));
    m.insert(std::make_pair(3, 30));
    for (auto it = m.begin(); it!= m.end(); ++it) {
        std::cout << it->first << " " << it->second << " ";
    }
    return 0;
}

6. 关联容器 unordered_set、关联容器 unordered_map(C++11及以上):

这两个容器分别是set和map的无序版本,它们基于哈希表实现。插入、删除和查找操作在平均情况下的时间复杂度为$O(1)$,但在最坏情况下可能为$O(n)$。由于是无序的,所以不会对元素进行自动排序。

#include <unordered_set>
#include <unordered_map>
#include <iostream>
int main() {
    std::unordered_set<int> us;
    us.insert(3);
    us.insert(1);
    us.insert(2);
    for (auto it = us.begin(); it!= us.end(); ++it) {
        std::cout << *it << " ";
    }
    std::unordered_map<int, int> um;
    um.insert(std::make_pair(1, 10));
    um.insert(std::make_pair(2, 20));
    um.insert(std::make_pair(3, 30));
    for (auto it = um.begin(); it!= um.end(); ++it) {
        std::cout << it->first << " " << it->second << " ";
    }
    return 0;
}

三. 算法(Algorithms)

1. 排序算法 std::sort:

对给定范围内的元素进行排序。它是一个快速排序的实现,平均时间复杂度为$O(n\log n)$,最坏情况下为$O(n^{2})$,但在实际应用中通常表现良好。

#include <algorithm>
#include <vector>
#include <iostream>
int main() {
    std::vector<int> v = {3, 1, 2};
    std::sort(v.begin(), v.end());
    for (auto num : v) {
        std::cout << num << " ";
    }
    return 0;
}

2. 查找算法 std::find:

功能:在给定范围内查找指定元素,如果找到则返回指向该元素的迭代器,否则返回范围末尾的迭代器。

#include <algorithm>
#include <vector>
#include <iostream>
int main() {
    std::vector<int> v = {1, 2, 3};
    auto it = std::find(v.begin(), v.end(), 2);
    if (it!= v.end()) {
        std::cout << "Element found";
    } else {
        std::cout << "Element not found";
    }
    return 0;
}

四. 迭代器(Iterators)

定义与功能:迭代器是一种类似于指针的对象,用于遍历容器中的元素。不同类型的容器提供不同类型的迭代器,但它们都遵循一定的规范,使得可以使用相同的算法来操作不同类型的容器。

分类:

输入迭代器:可以从容器中读取元素,支持++(向前移动)操作和*(解引用)操作,但不支持多次解引用同一元素,也不支持--(向后移动)操作。

输出迭代器:用于向容器中写入元素,支持++操作和*操作,但解引用操作只能用于赋值,不能读取元素。

前向迭代器:兼具输入迭代器和输出迭代器的功能,并且支持多次解引用同一元素。

双向迭代器:在前向迭代器的基础上,支持--操作,可以双向遍历容器。

随机访问迭代器:除了双向迭代器的功能外,还支持随机访问元素,如it + n、it - n等操作,像vector容器提供的迭代器就是随机访问迭代器。

五. 函数对象(Function objects)、适配器(Adapters)和分配器(Allocators)

函数对象(Function objects):也称为仿函数,是一个类,其重载了()运算符,使得类的对象可以像函数一样被调用。例如:

class Add {
    public:
        int operator()(int a, int b) {
            return a + b;
        }
};
int main() {
    Add add;
    int result = add(1, 2);
    std::cout << result << " ";
    return 0;
}

适配器(Adapters):用于修改或组合其他组件的行为。例如,std::bind是一个函数适配器,它可以绑定函数的部分参数,创建一个新的可调用对象。

分配器(Allocators):负责为容器分配和回收内存。默认的分配器std::allocator在大多数情况下能够满足需求,但在一些特殊场景下,如需要定制内存分配策略时,可以创建自己的分配器。

C++编程语言基础

C++标准模板库(STL)容器、算法、迭代器