当前位置: 首页 > article >正文

C++ 标准模板库(STL)教程

欢迎来到C++标准模板库(STL)的学习之旅!STL是C++的一部分,提供了一套通用的、可重用的模板类和函数,用于处理常见的数据结构和算法。通过掌握STL,您可以大大提高编程效率和代码质量。本文将以通俗易懂的方式,全面介绍C++ STL的各个组成部分及其应用。

目录

  1. 什么是C++ STL?
  2. STL的组成部分
    • 容器(Containers)
      • 序列容器(Sequence Containers)
        • vector
        • list
        • deque
        • array
      • 关联容器(Associative Containers)
        • set
        • map
        • multiset
        • multimap
      • 无序关联容器(Unordered Associative Containers)
        • unordered_set
        • unordered_map
      • 容器适配器(Container Adapters)
        • stack
        • queue
        • priority_queue
    • 迭代器(Iterators)
      • 迭代器类型
      • 迭代器的使用
    • 算法(Algorithms)
      • 常用算法示例
    • 函数对象与Lambda表达式(Function Objects and Lambda Expressions)
  3. STL的使用示例
    • 使用vectorsort算法
    • 使用map进行键值对存储
    • 使用find_if和Lambda表达式
  4. STL最佳实践
    • 选择合适的容器
    • 避免不必要的拷贝
    • 充分利用算法
  5. 总结
  6. 推荐学习资源

1. 什么是C++ STL?

STL(Standard Template Library,标准模板库)是C++标准库的一部分,提供了一套通用的、可重用的模板类和函数,用于处理常见的数据结构(如数组、链表、哈希表等)和算法(如排序、搜索、遍历等)。STL的设计理念是“泛型编程(Generic Programming)”,即编写与类型无关的代码,通过模板参数在编译时指定具体类型。

STL的优势:

  • 高效性:STL的实现通常经过高度优化,性能优越。
  • 可重用性:通过模板,STL的组件可以适用于多种数据类型。
  • 简洁性:减少了重复代码,提高了开发效率。
  • 一致性:提供统一的接口和用法,降低了学习成本。

2. STL的组成部分

STL主要由以下几个部分组成:

  1. 容器(Containers):用于存储和组织数据的类模板。
  2. 迭代器(Iterators):用于访问和遍历容器中的元素。
  3. 算法(Algorithms):用于操作容器中元素的函数模板。
  4. 函数对象与Lambda表达式(Function Objects and Lambda Expressions):用于定义自定义操作的对象和匿名函数。

2.1 容器(Containers)

容器是STL的核心部分,提供了多种数据结构来存储和组织数据。STL的容器分为以下几类:

2.1.1 序列容器(Sequence Containers)

序列容器用于存储有序的数据序列,支持元素的插入、删除和访问。

vector

vector是一个动态数组,支持随机访问,元素在内存中连续存储,适合需要频繁访问元素的场景。

示例:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> numbers = {1, 2, 3, 4, 5};

    // 添加元素
    numbers.push_back(6);

    // 访问元素
    cout << "Element at index 2: " << numbers[2] << endl;

    // 遍历
    cout << "All elements: ";
    for(auto num : numbers) {
        cout << num << " ";
    }
    cout << endl;

    return 0;
}

输出:

Element at index 2: 3
All elements: 1 2 3 4 5 6 
list

list是一个双向链表,支持在任意位置高效地插入和删除元素,但不支持随机访问。

示例:

#include <iostream>
#include <list>
using namespace std;

int main() {
    list<string> fruits = {"Apple", "Banana", "Cherry"};

    // 添加元素
    fruits.push_back("Date");
    fruits.push_front("Elderberry");

    // 遍历
    cout << "Fruits: ";
    for(auto it = fruits.begin(); it != fruits.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;

    return 0;
}

输出:

Fruits: Elderberry Apple Banana Cherry Date 
deque

deque(双端队列)支持在头尾高效地插入和删除元素,兼具vector的随机访问能力。

示例:

#include <iostream>
#include <deque>
using namespace std;

int main() {
    deque<int> dq = {10, 20, 30};

    // 添加元素
    dq.push_back(40);
    dq.push_front(5);

    // 访问元素
    cout << "Element at index 1: " << dq[1] << endl;

    // 遍历
    cout << "Deque elements: ";
    for(auto num : dq) {
        cout << num << " ";
    }
    cout << endl;

    return 0;
}

输出:

Element at index 1: 10
Deque elements: 5 10 20 30 40 
array

array是一个固定大小的数组,大小在编译时确定,适合存储固定数量的元素。

示例:

#include <iostream>
#include <array>
using namespace std;

int main() {
    array<int, 5> arr = {1, 2, 3, 4, 5};

    // 访问元素
    cout << "Element at index 3: " << arr[3] << endl;

    // 遍历
    cout << "Array elements: ";
    for(auto it = arr.begin(); it != arr.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;

    return 0;
}

输出:

Element at index 3: 4
Array elements: 1 2 3 4 5 
2.1.2 关联容器(Associative Containers)

关联容器用于存储有序的键值对,支持高效的查找、插入和删除操作。

set

set是一个集合,存储唯一的、有序的元素,自动排序。

示例:

#include <iostream>
#include <set>
using namespace std;

int main() {
    set<int> s = {4, 1, 3, 2};

    // 添加元素
    s.insert(5);
    s.insert(3); // 重复元素不会插入

    // 遍历
    cout << "Set elements: ";
    for(auto it : s) {
        cout << it << " ";
    }
    cout << endl;

    return 0;
}

输出:

Set elements: 1 2 3 4 5 
map

map是一个键值对集合,键是唯一的,自动排序。适合需要通过键快速查找值的场景。

示例:

#include <iostream>
#include <map>
using namespace std;

int main() {
    map<string, int> age;

    // 添加键值对
    age["Alice"] = 30;
    age["Bob"] = 25;
    age["Charlie"] = 35;

    // 访问元素
    cout << "Alice's age: " << age["Alice"] << endl;

    // 遍历
    cout << "All ages:" << endl;
    for(auto it : age) {
        cout << it.first << " is " << it.second << " years old." << endl;
    }

    return 0;
}

输出:

Alice's age: 30
All ages:
Alice is 30 years old.
Bob is 25 years old.
Charlie is 35 years old.
multisetmultimap

multisetmultimap允许存储重复的元素或键值对,适用于需要存储多重关联的场景。

示例(multiset):

#include <iostream>
#include <set>
using namespace std;

int main() {
    multiset<int> ms = {1, 2, 2, 3, 4};

    // 添加元素
    ms.insert(2);
    ms.insert(5);

    // 遍历
    cout << "Multiset elements: ";
    for(auto it : ms) {
        cout << it << " ";
    }
    cout << endl;

    return 0;
}

输出:

Multiset elements: 1 2 2 2 3 4 5 
2.1.3 无序关联容器(Unordered Associative Containers)

无序关联容器使用哈希表实现,提供平均常数时间的查找、插入和删除操作,但不保证元素的顺序。

unordered_set

unordered_set类似于set,但不保证元素的顺序,查找速度更快。

示例:

#include <iostream>
#include <unordered_set>
using namespace std;

int main() {
    unordered_set<int> us = {4, 1, 3, 2};

    // 添加元素
    us.insert(5);
    us.insert(3); // 重复元素不会插入

    // 遍历
    cout << "Unordered Set elements: ";
    for(auto it : us) {
        cout << it << " ";
    }
    cout << endl;

    return 0;
}

输出:

Unordered Set elements: 1 2 3 4 5 
unordered_map

unordered_map类似于map,但不保证键值对的顺序,查找速度更快。

示例:

#include <iostream>
#include <unordered_map>
using namespace std;

int main() {
    unordered_map<string, int> um;

    // 添加键值对
    um["Alice"] = 30;
    um["Bob"] = 25;
    um["Charlie"] = 35;

    // 访问元素
    cout << "Bob's age: " << um["Bob"] << endl;

    // 遍历
    cout << "All ages in unordered_map:" << endl;
    for(auto it : um) {
        cout << it.first << " is " << it.second << " years old." << endl;
    }

    return 0;
}

输出:

Bob's age: 25
All ages in unordered_map:
Charlie is 35 years old.
Alice is 30 years old.
Bob is 25 years old.
2.1.4 容器适配器(Container Adapters)

容器适配器是基于已有容器实现的特定数据结构接口,主要包括stackqueuepriority_queue

stack

stack是一种后进先出(LIFO)的数据结构,只允许在一端(栈顶)进行插入和删除操作。

示例:

#include <iostream>
#include <stack>
using namespace std;

int main() {
    stack<int> s;

    // 添加元素
    s.push(10);
    s.push(20);
    s.push(30);

    // 遍历栈
    cout << "Stack elements: ";
    while(!s.empty()) {
        cout << s.top() << " ";
        s.pop();
    }
    cout << endl;

    return 0;
}

输出:

Stack elements: 30 20 10 
queue

queue是一种先进先出(FIFO)的数据结构,允许在一端(队尾)插入,在另一端(队头)删除。

示例:

#include <iostream>
#include <queue>
using namespace std;

int main() {
    queue<string> q;

    // 添加元素
    q.push("First");
    q.push("Second");
    q.push("Third");

    // 遍历队列
    cout << "Queue elements: ";
    while(!q.empty()) {
        cout << q.front() << " ";
        q.pop();
    }
    cout << endl;

    return 0;
}

输出:

Queue elements: First Second Third 
priority_queue

priority_queue是一种优先级队列,元素按优先级顺序排列,默认情况下是最大堆,最大的元素位于队首。

示例:

#include <iostream>
#include <queue>
using namespace std;

int main() {
    priority_queue<int> pq;

    // 添加元素
    pq.push(30);
    pq.push(10);
    pq.push(20);

    // 遍历优先级队列
    cout << "Priority Queue elements: ";
    while(!pq.empty()) {
        cout << pq.top() << " ";
        pq.pop();
    }
    cout << endl;

    return 0;
}

输出:

Priority Queue elements: 30 20 10 

2.2 迭代器(Iterators)

迭代器是STL中用于访问和遍历容器元素的对象,类似于指针。通过迭代器,您可以在不关心容器内部结构的情况下,遍历和操作容器中的元素。

2.2.1 迭代器类型

STL提供了多种迭代器类型,适用于不同的容器和操作:

  • 输入迭代器(Input Iterators):只允许读取数据,单向遍历。
  • 输出迭代器(Output Iterators):只允许写入数据,单向遍历。
  • 前向迭代器(Forward Iterators):支持读取和写入数据,单向遍历。
  • 双向迭代器(Bidirectional Iterators):支持双向遍历(前进和后退)。
  • 随机访问迭代器(Random Access Iterators):支持任意位置访问和多种算术操作。
2.2.2 迭代器的使用

示例:使用迭代器遍历vector

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> numbers = {1, 2, 3, 4, 5};

    // 使用迭代器遍历
    cout << "Vector elements: ";
    for(vector<int>::iterator it = numbers.begin(); it != numbers.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;

    return 0;
}

输出:

Vector elements: 1 2 3 4 5 

示例:使用auto关键字简化迭代器类型

#include <iostream>
#include <list>
using namespace std;

int main() {
    list<string> fruits = {"Apple", "Banana", "Cherry"};

    // 使用auto简化迭代器类型
    cout << "List elements: ";
    for(auto it = fruits.begin(); it != fruits.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;

    return 0;
}

输出:

List elements: Apple Banana Cherry 

2.3 算法(Algorithms)

STL提供了大量的算法,涵盖排序、搜索、变换、数值计算等操作。这些算法可以与容器和迭代器无缝结合,提高代码的简洁性和效率。

2.3.1 常用算法示例
sort

对容器中的元素进行排序,默认按照升序排列。

示例:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> numbers = {4, 2, 5, 1, 3};

    // 排序前
    cout << "Before sort: ";
    for(auto num : numbers) cout << num << " ";
    cout << endl;

    // 使用sort算法排序
    sort(numbers.begin(), numbers.end());

    // 排序后
    cout << "After sort: ";
    for(auto num : numbers) cout << num << " ";
    cout << endl;

    return 0;
}

输出:

Before sort: 4 2 5 1 3 
After sort: 1 2 3 4 5 
find

在容器中查找特定元素,返回指向该元素的迭代器,如果未找到则返回结束迭代器。

示例:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<string> names = {"Alice", "Bob", "Charlie", "Diana"};

    // 查找"Charlie"
    auto it = find(names.begin(), names.end(), "Charlie");

    if(it != names.end()) {
        cout << "Found: " << *it << endl;
    } else {
        cout << "Not Found!" << endl;
    }

    return 0;
}

输出:

Found: Charlie
for_each

对容器中的每个元素应用指定的函数。

示例:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 函数对象
struct Print {
    void operator()(int x) const {
        cout << x << " ";
    }
};

int main() {
    vector<int> numbers = {1, 2, 3, 4, 5};

    // 使用for_each和函数对象
    cout << "Elements: ";
    for_each(numbers.begin(), numbers.end(), Print());
    cout << endl;

    return 0;
}

输出:

Elements: 1 2 3 4 5 
accumulate

计算容器中所有元素的累加和(需要包含头文件<numeric>)。

示例:

#include <iostream>
#include <vector>
#include <numeric>
using namespace std;

int main() {
    vector<int> numbers = {1, 2, 3, 4, 5};

    // 计算总和
    int sum = accumulate(numbers.begin(), numbers.end(), 0);

    cout << "Sum: " << sum << endl;

    return 0;
}

输出:

Sum: 15

2.4 函数对象与Lambda表达式(Function Objects and Lambda Expressions)

2.4.1 函数对象(Function Objects)

函数对象是重载了operator()的类,可以像函数一样调用。它们通常用于算法中传递自定义操作。

示例:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 函数对象,用于打印元素
struct Print {
    void operator()(int x) const {
        cout << x << " ";
    }
};

int main() {
    vector<int> numbers = {1, 2, 3, 4, 5};

    // 使用for_each和函数对象
    cout << "Elements: ";
    for_each(numbers.begin(), numbers.end(), Print());
    cout << endl;

    return 0;
}

输出:

Elements: 1 2 3 4 5 
2.4.2 Lambda表达式

Lambda表达式是一种轻量级的函数对象,可以在需要函数的地方定义匿名函数,简化代码。

示例:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> numbers = {1, 2, 3, 4, 5};

    // 使用for_each和Lambda表达式
    cout << "Elements: ";
    for_each(numbers.begin(), numbers.end(), [](int x) {
        cout << x << " ";
    });
    cout << endl;

    // 使用sort和Lambda表达式进行自定义排序(降序)
    sort(numbers.begin(), numbers.end(), [](int a, int b) -> bool {
        return a > b;
    });

    cout << "Sorted (descending): ";
    for(auto num : numbers) cout << num << " ";
    cout << endl;

    return 0;
}

输出:

Elements: 1 2 3 4 5 
Sorted (descending): 5 4 3 2 1 

3. STL的使用示例

通过实际的代码示例,深入理解STL的应用。

3.1 使用vectorsort算法

示例:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    // 创建并初始化vector
    vector<int> nums = {4, 2, 5, 1, 3};

    // 打印原始元素
    cout << "Original vector: ";
    for(auto num : nums) cout << num << " ";
    cout << endl;

    // 排序
    sort(nums.begin(), nums.end());

    // 打印排序后的元素
    cout << "Sorted vector: ";
    for(auto num : nums) cout << num << " ";
    cout << endl;

    return 0;
}

输出:

Original vector: 4 2 5 1 3 
Sorted vector: 1 2 3 4 5 

3.2 使用map进行键值对存储

示例:

#include <iostream>
#include <map>
using namespace std;

int main() {
    // 创建map并插入键值对
    map<string, int> ageMap;
    ageMap["Alice"] = 30;
    ageMap["Bob"] = 25;
    ageMap["Charlie"] = 35;

    // 访问和修改元素
    cout << "Alice's age: " << ageMap["Alice"] << endl;
    ageMap["Bob"] = 26;

    // 遍历map
    cout << "All ages:" << endl;
    for(auto it = ageMap.begin(); it != ageMap.end(); ++it) {
        cout << it->first << " is " << it->second << " years old." << endl;
    }

    return 0;
}

输出:

Alice's age: 30
All ages:
Alice is 30 years old.
Bob is 26 years old.
Charlie is 35 years old.

3.3 使用find_if和Lambda表达式

示例:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> numbers = {10, 20, 30, 40, 50};

    // 查找第一个大于25的元素
    auto it = find_if(numbers.begin(), numbers.end(), [](int x) {
        return x > 25;
    });

    if(it != numbers.end()) {
        cout << "First number > 25: " << *it << endl;
    } else {
        cout << "No number > 25 found." << endl;
    }

    return 0;
}

输出:

First number > 25: 30

4. STL最佳实践

为了充分利用STL的优势,以下是一些最佳实践建议:

4.1 选择合适的容器

不同的容器适用于不同的场景:

  • vector:适合需要频繁随机访问和在末尾添加元素的场景。
  • list:适合需要频繁在任意位置插入和删除元素的场景。
  • deque:适合需要在头尾进行高效插入和删除,并且需要随机访问的场景。
  • map:适合需要通过键快速查找值的场景。
  • unordered_map:适合需要高效查找但不关心顺序的场景。

4.2 避免不必要的拷贝

通过使用引用或指针,避免在容器和算法中进行不必要的拷贝操作,提升性能。

示例:使用引用遍历vector

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> nums = {1, 2, 3, 4, 5};

    // 使用引用避免拷贝
    for(auto &num : nums) {
        num *= 2; // 修改原始元素
    }

    // 打印结果
    for(auto num : nums) cout << num << " ";
    cout << endl;

    return 0;
}

输出:

2 4 6 8 10 

4.3 充分利用算法

STL提供了丰富的算法库,通过算法可以大大简化代码并提升效率。

示例:使用transform算法进行元素变换

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> nums = {1, 2, 3, 4, 5};
    vector<int> squared(nums.size());

    // 使用transform算法计算平方
    transform(nums.begin(), nums.end(), squared.begin(), [](int x) {
        return x * x;
    });

    // 打印结果
    cout << "Squared numbers: ";
    for(auto num : squared) cout << num << " ";
    cout << endl;

    return 0;
}

输出:

Squared numbers: 1 4 9 16 25 

5. 总结

C++标准模板库(STL)为开发者提供了一套高效、可重用的工具,用于处理常见的数据结构和算法。通过熟练掌握STL的容器、迭代器、算法以及函数对象,您可以编写出更简洁、更高效的代码。以下是本文的关键要点:

  • 容器:选择合适的容器是高效编程的基础。
  • 迭代器:理解迭代器的类型和用法,有助于灵活地遍历和操作容器。
  • 算法:充分利用STL提供的算法库,简化代码并提升性能。
  • 函数对象与Lambda:通过自定义操作和匿名函数,增强算法的灵活性。

通过不断练习和实际应用,您将能够充分发挥STL的优势,提升C++编程技能。


6. 推荐学习资源

6.1 书籍

  • 《C++标准库》(Nicolai M. Josuttis)
    • 深入介绍C++标准库的各个组成部分,包括STL容器、迭代器和算法。
  • 《Effective STL》(Scott Meyers)
    • 提供了50条关于如何有效使用STL的建议,适合有一定基础的开发者。
  • 《STL源码剖析》(侯捷)
    • 通过源码分析深入理解STL的内部实现机制。

6.2 在线教程与文档

  • cppreference.com

    • STL Overview
    • 提供全面的C++标准库参考文档,涵盖所有STL组件。
  • GeeksforGeeks

    • C++ STL Tutorial
    • 提供详细的STL教程和代码示例,适合初学者。
  • LearnCPP.com

    • C++ Standard Template Library
    • 系统性讲解STL的各个部分和使用方法。

6.3 视频课程

  • YouTube - The Cherno C++ Series

    • The Cherno's C++ Playlist
    • 包含C++基础和STL相关的视频教程。
  • Udemy

    • C++ STL Course
    • 提供多种C++ STL的在线课程,结合实际项目进行讲解。

6.4 实践平台

  • LeetCode

    • LeetCode C++ Problems
    • 通过解决编程题目,应用STL容器和算法,提升实战能力。
  • HackerRank

    • HackerRank C++ Domain
    • 提供丰富的C++练习题,涵盖STL的各个方面。
  • Codeforces

    • Codeforces Problems
    • 参与竞赛和解决问题,锻炼使用STL的技巧。

http://www.kler.cn/news/360483.html

相关文章:

  • 电影评论网站开发:Spring Boot技术详解
  • ThinkPad T480拆机屏幕改装:便携式显示器DIY指南
  • 小白向的源码开发详解:直播带货系统与电商平台搭建指南
  • 每日一题|3185. 构成整天的下标对数目 II|数组取代hash
  • MacOS13虚拟机VMware Workstation Pro 16安装
  • 【LeetCode HOT 100】详细题解之二分查找篇
  • 后端:唯一ID有哪些生成方式
  • mybatis二级缓存知识
  • 012_django基于大数据的高校新生数据可视化分析系统2024_4x13gn6t (1)
  • 通过PHP与API的结合,开启电商数据集成的新篇章
  • Richtek | 用于智能门铃的电源管理解决方案
  • 老机MicroServer Gen8再玩 OCP万兆光口+IT直通
  • Windows下配置Nginx和PHP
  • 有趣的css - 跷跷板加载动画
  • 【Vercel】Vercel静态部署踩坑
  • 从零开始学PHP之变量作用域数据类型
  • 天锐绿盾 vs Ping32:企业级加密软件大比拼
  • 分布式---CAPBASE理论
  • 基于深度学习的设备异常检测与预测性维护
  • 你知道吗?这个岗位只招2人,但HR那边却收到了1w份简历