C++青少年简明教程:STL入门介绍

C++青少年简明教程:STL入门介绍

STL(Standard Template Library),这是C++标准库(Standard Library)之一,提供了丰富的模板类和函数,包括容器(如vector、deque、list等)、算法(如排序、搜索等)和迭代器等。学生可以学习如何使用STL来简化程序开发,并提高代码的可重用性。

STL已经成为C++开发的重要基础,广泛应用于包括编程竞赛、游戏开发、高性能计算等众多领域。

C++的STL(Standard Template Library)包含了很多内容,对于初学者来说,入门STL并不需要一次性掌握所有内容,而是应该分阶段、有重点地学习。

常用的容器(Containers

序列容器(Sequence Containers):管理数据集合的顺序结构。典型的序列容器包括vector(动态数组)、deque(双端队列)、list(双向链表)。

关联容器(Associative Containers):支持快速元素查找和访问。主要的关联容器有set、map。

无序关联容器(Unordered Associative Containers):基于哈希表实现,可以提供平均时间复杂度为常数的元素查找。包括unordered_set、unordered_map。

容器适配器(Container Adaptors):利用序列容器实现特定接口的容器。包括stack、queue和priority_queue。

学习容器时,可以从以下几点入手:

容器的基本操作:插入、删除、访问元素

容器的迭代器:如何使用迭代器遍历和操作容器中的元素

容器的特性:比如vector的动态扩展能力,set的元素唯一性和有序性

容器部分主要由头文件<vector>,<list>,<deque>,<set>,<map>,<stack>和<queue>组成。对于常用的一些容器和容器适配器(可以看作由其它容器实现的容器),可以通过下表总结一下它们和相应头文件的对应关系。

1. vector(向量)

概念:vector就像一个能够增长的数组,你可以在数组的尾部高效地添加或删除元素。

用途:当你需要一个可变大小的数组,或者你只需要在一端添加或删除元素时。

示例:

  std::vector<int> vec;

  vec.push_back(10); // 向vec的尾部添加一个元素

  vec.push_back(20);

  std::cout << vec[1]; // 打印: 20

下面给出一个完整的简单例子,演示了如何创建vector容器、插入元素并遍历容器中的元素:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> myVector;

    // 在向量末尾插入元素
    myVector.push_back(1);
    myVector.push_back(2);
    myVector.push_back(3);

    // 遍历向量并输出元素
    for (int i = 0; i < myVector.size(); i++) {
        std::cout << myVector[i] << " ";
    }

    return 0;
}

输出:

1 2 3

2. list(列表)

概念:list是一个双向链表,允许从两端快速添加或删除元素,但是随机访问较慢。

用途:当你需要频繁在列表的中间插入或删除元素时。

示例:

  std::list<int> lst;

  lst.push_back(10);

  lst.push_front(20); // 在list的前面添加一个元素

下面给出一个完整的简单例子,演示了如何创建list容器、插入元素并遍历容器中的元素:

#include <iostream>
#include <list>

int main() {
    std::list<int> myList;

    // 在列表末尾插入元素
    myList.push_back(1);
    myList.push_back(2);
    myList.push_back(3);

    // 遍历列表并输出元素
    for (auto it = myList.begin(); it != myList.end(); ++it) {
        std::cout << *it << " ";
    }

    return 0;
}

输出:

1 2 3

3. deque(双端队列)

概念:deque支持从头部和尾部高效地添加或删除元素。

用途:当你需要一个队列,并且想要在两端都能快速添加或删除数据时。

示例:

  std::deque<int> deq;

  deq.push_back(10);

  deq.push_front(20); // 在deque的前面添加一个元素

下面给出一个完整的简单例子,演示了如何创建deque容器、插入元素并遍历容器中的元素:

#include <iostream>
#include <deque>

int main() {
    std::deque<int> myDeque;

    // 在双端队列末尾插入元素
    myDeque.push_back(1);
    myDeque.push_back(2);
    myDeque.push_back(3);

    // 在双端队列开头插入元素
    myDeque.push_front(0);

    // 遍历双端队列并输出元素
    for (int i = 0; i < myDeque.size(); i++) {
        std::cout << myDeque[i] << " ";
    }

    return 0;
}

输出:

0 1 2 3

4. map(映射)

概念:map是一个键值对集合,它是按照键的顺序排序的,每个键只能出现一次。

用途:当你需要根据键快速查找值时,如字典。

示例:

  std::map<std::string, int> scores;

  scores["Alice"] = 90;

  scores["Bob"] = 85; // 通过key "Bob" 设置对应的值为85

下面给出一个完整的简单例子,演示了如何创建map容器、插入元素并遍历容器中的元素:

#include <iostream>
#include <map>

int main() {
    std::map<int, std::string> myMap;

    // 插入键值对
    myMap[1] = "apple";
    myMap[2] = "banana";
    myMap[3] = "orange";

    // 遍历映射并输出键值对
    for (auto it = myMap.begin(); it != myMap.end(); ++it) {
        std::cout << "Key: " << it->first << ", Value: " << it->second << std::endl;
    }

    return 0;
}

输出:

Key: 1, Value: apple
Key: 2, Value: banana
Key: 3, Value: orange

5. set(集合)

概念:set是一个包含唯一元素的集合,自动为你排序。

用途:当你需要存储无重复值的集合,并且希望自动按顺序排列时。

示例:

  std::set<int> nums;

  nums.insert(10);

  nums.insert(20);

  nums.insert(10); // 10已存在,不会被加入

下面给出一个完整的简单例子,演示了如何创建set容器、插入元素并遍历容器中的元素:

#include <iostream>
#include <set>

int main() {
    std::set<int> mySet;

    // 插入元素
    mySet.insert(3);
    mySet.insert(1);
    mySet.insert(2);

    // 遍历集合并输出元素
    for (auto it = mySet.begin(); it != mySet.end(); ++it) {
        std::cout << *it << " ";
    }

    return 0;
}

输出:

1 2 3

迭代器(Iterators

迭代器,是与STL容器交互的主要方式。被设计用于访问容器中的元素,类似于指针。根据功能不同,迭代器分为五种类型:输入迭代器、输出迭代器、前向迭代器、双向迭代器和随机访问迭代器。STL容器提供了相应的迭代器,以实现对其元素的遍历和操作。

了解迭代器的分类及其使用方法:

输入迭代器、输出迭代器、前向迭代器、双向迭代器、随机访问迭代器

练习如何使用迭代器遍历容器,并结合算法实现复杂操作

STL中有多种类型的迭代器,每种迭代器都有不同的功能和用途:

输入迭代器(Input Iterator):只读访问容器中的元素,主要用于从容器中读取数据。

输出迭代器(Output Iterator):只写访问容器中的元素,主要用于向容器中写入数据。

前向迭代器(Forward Iterator):可以读写元素,并且可以在容器中向前遍历。

双向迭代器(Bidirectional Iterator):除了前向迭代的能力外,还可以向后遍历。

随机访问迭代器(Random Access Iterator):支持双向迭代,并且可以直接跳到容器中的任何元素,类似于指针。

常见的迭代器操作

迭代器有一些常用的操作方法,这些方法类似于指针的操作:

*it:解引用迭代器,访问其指向的元素。

it->member:访问迭代器指向元素的成员。

++it 或 it++:将迭代器移动到下一个元素。

--it 或 it--:将迭代器移动到前一个元素(仅限双向迭代器和随机访问迭代器)。

it1 == it2:判断两个迭代器是否指向同一个元素。

it1 != it2:判断两个迭代器是否指向不同的元素。

在C++中,迭代器(iterator)提供了一种方法,使得我们能够顺序访问一个容器(如数组、列表、向量等)中的各个元素,而不需要了解容器底层的具体实现。

通过使用迭代器,你可以遍历容器并访问其中的元素,而不需要关心底层数据结构的具体实现细节。迭代器提供了一组通用的操作接口,如移动到下一个元素、获取当前元素的值等。这样,你可以使用相同的代码逻辑来处理不同类型的容器,提高了代码的可复用性和灵活性。

需要注意的是,不同类型的容器可能具有不同类型的迭代器,因为它们的内部结构和访问方式可能不同。因此,在使用迭代器时,你需要根据具体的容器类型选择相应的迭代器类型。

下面是一些常见的C++容器及其对应的迭代器类型的示例:

数组(Array):对于普通的C数组,可以使用指针作为迭代器来访问元素。例如:

#include <iostream>  
 
int main() {  
    int arr[] = {1, 2, 3, 4, 5};  
    int* it = arr; // it 是指向数组首元素的指针(迭代器)  
  
    // 使用指针作为迭代器遍历数组  
    for (; it != arr + sizeof(arr) / sizeof(arr[0]); ++it) {  
        std::cout << *it << ' ';  
    }  
  
    std::cout << std::endl;  
  
    return 0;  
}

这个示例中,it 是一个指向数组 arr 首元素的指针,它被用作迭代器来遍历数组。循环条件 it != arr + sizeof(arr) / sizeof(arr[0]) 用来确保不会超出数组的边界。sizeof(arr) / sizeof(arr[0]) 计算了数组的元素数量,arr + 数组元素数量 则指向数组的末尾之后的位置。

输出:

1 2 3 4 5

标准库容器(Standard Library Containers):不同的标准库容器有不同类型的迭代器。

std::vector:使用随机访问迭代器(random access iterator),可以通过指针或下标进行元素访问。例如:

#include <iostream>  
#include <vector>  
  
int main() {  
    // 创建一个 std::vector 并初始化  
    std::vector<int> vec = {1, 2, 3, 4, 5};  
  
    // 获取指向 vector 首元素的迭代器  
    std::vector<int>::iterator it = vec.begin();  
  
    // 使用迭代器遍历 vector  
    for (; it != vec.end(); ++it) {  
        std::cout << *it << ' '; // 使用 * 操作符解引用迭代器以访问元素  
    }  
    std::cout << std::endl;  
  
    // 使用随机访问迭代器的特性  
    // 直接访问第3个元素(注意:索引从0开始)  
    std::cout << "The 3rd element is: " << vec[2] << std::endl;  
  
    // 使用迭代器进行随机访问  
    // 注意:迭代器也可以像指针一样进行算术运算  
    it = vec.begin() + 2; // 将迭代器移动到第3个元素  
    std::cout << "The 3rd element using iterator is: " << *it << std::endl;  
  
    // 反向迭代器(reverse iterator)示例  
    // 使用 rbegin() 和 rend() 获取反向迭代器  
    std::cout << "Elements in reverse order: ";  
    std::vector<int>::reverse_iterator rit = vec.rbegin();  
    for (; rit != vec.rend(); ++rit) {  
        std::cout << *rit << ' ';  
    }  
    std::cout << std::endl;  
  
    return 0;  
}

输出:

1 2 3 4 5
The 3rd element is: 3
The 3rd element using iterator is: 3
Elements in reverse order: 5 4 3 2 1

std::list:使用双向迭代器(bidirectional iterator),只支持前移和后移操作。例如:

#include <iostream>  
#include <list>  
  
int main() {  
    // 创建一个 std::list 并初始化  
    std::list<int> lst = {1, 2, 3, 4, 5};  
  
    // 获取指向 list 首元素的迭代器  
    std::list<int>::iterator it = lst.begin();  
  
    // 使用迭代器遍历 list  
    std::cout << "Elements in forward order: ";  
    for (; it != lst.end(); ++it) {  
        std::cout << *it << ' '; // 使用 * 操作符解引用迭代器以访问元素  
    }  
    std::cout << std::endl;  
  
    // 使用双向迭代器的特性向后遍历  
    // 先将迭代器指向 list 的尾元素  
    it = lst.end();  
    // 注意:end() 返回的迭代器指向最后一个元素之后的位置  
    // 因此,我们需要先递减迭代器以访问最后一个元素  
    if (it != lst.begin()) {  
        --it; // 将迭代器向后移动一个位置  
  
        std::cout << "Elements in backward order: ";  
        // 使用 -- 操作符将迭代器向后移动  
        for (; it != lst.begin(); --it) {  
            std::cout << *it << ' ';  
        }  
        std::cout << *lst.begin(); // 打印第一个元素  
        std::cout << std::endl;  
    }  
  
    return 0;  
}

在上面的示例中,我们首先使用正向迭代器遍历 std::list 中的所有元素。然后,我们使用双向迭代器的特性来向后遍历列表。注意,lst.end() 返回的迭代器指向列表末尾的下一个位置(即不指向任何有效元素),因此在开始向后遍历之前,我们需要先递减迭代器以指向最后一个元素。

还要注意的是,在向后遍历的循环中,我们使用 it != lst.begin() 作为循环条件,因为当迭代器到达列表的开始时,我们不能再递减它(这会导致迭代器无效)。因此,在循环结束后,我们需要单独打印出列表的第一个元素。

双向迭代器不支持随机访问,所以你不能使用 it + n 这样的表达式来直接跳转到列表中的第 n 个元素。你只能通过连续地递增或递减迭代器来遍历列表。

输出:

Elements in forward order: 1 2 3 4 5
Elements in backward order: 5 4 3 2 1

上面这些示例只是展示了一部分常见容器的迭代器类型,实际上C++标准库提供了多种容器和对应的迭代器,每种容器都有不同的特点和适用场景。

上面这些示例只是展示了一部分常见容器的迭代器类型,实际上C++标准库提供了多种容器和对应的迭代器,每种容器都有不同的特点和适用场景。

算法(Algorithms

提供了一系列执行各种操作(如排序、搜索、修改、复制、删除等)的函数模板。这些算法是泛型的,能够与STL容器和迭代器一起工作

STL提供了大量的算法,理解并使用这些算法能大大提高编程效率。<algorithm>头文件包含了多种用于操作序列(例如数组、向量等)的通用算法,如:

排序算法如:sort、stable_sort

搜索算法如:find、binary_search

等等

<algorithm> 头文件中一些常用的算法很多,这些算法通常与迭代器一起使用,可以应用于任何支持迭代器的容器,如 std::vector、std::list、std::array 等

STL中的算法和容器都是经过优化的,可以充分利用计算机的性能。使用STL可以大大减少代码量,使代码更加简洁易读。由于STL的广泛使用和成熟的实现,其错误率相对较低,有助于减少调试时间。熟练掌握STL的使用可以大大提高编程效率和代码质量。

例1、对vector进行排序

#include <iostream>  
#include <vector>  
#include <algorithm>  
  
int main() {  
    std::vector<int> nums = {5, 3, 1, 4, 2};  
  
    // 使用STL的sort算法对vector进行排序  
    std::sort(nums.begin(), nums.end());  
  
    // 遍历并输出排序后的vector  
    for (int num : nums) {  
        std::cout << num << ' ';  
    }  
    std::cout << std::endl;  
  
    return 0;  
}

输出:

1 2 3 4 5

2、搜索vector中的元素

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

int main() {
    std::vector<int> myVector = {3, 1, 4, 1, 5, 9, 2, 6, 5};

    // 使用std::find查找元素
    auto it = std::find(myVector.begin(), myVector.end(), 5);

    if (it != myVector.end()) {
        std::cout << "Found 5 at position: " << std::distance(myVector.begin(), it) << std::endl;
    } else {
        std::cout << "5 not found" << std::endl;
    }

    return 0;
}

输出:

Found 5 at position: 4

附录

C++之STL(标准模板库)介绍https://blog.csdn.net/cnds123/article/details/118765133

各种C++ STL容器全解析 https://www.cnblogs.com/fusiwei/p/11823234.html

  • 16
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学习&实践爱好者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值