C++进阶语法——STL 标准模板库(下)(Standard Template Library)【学习笔记(七)】

这篇具有很好参考价值的文章主要介绍了C++进阶语法——STL 标准模板库(下)(Standard Template Library)【学习笔记(七)】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

STL 代码示例

1、迭代器

  • 迭代器可以将任意的容器抽象成一个序列,可以使用迭代器遍历容器中的元素
  • 迭代器设计的目的是为了解决容器与算法之间的耦合问题,与指针类似,可以通过迭代器访问容器中的元素
  • 迭代器的声明方式为:容器类型::iterator 变量名称可以理解为一个普通的指针,比如:
    • std::vector<int>::iterator it;
    • std::list<int>::iterator it;
    • std::map<int, int>::iterator it;
    • std::set<int>::iterator it;

代码:

/*
* 迭代器示例
* 迭代器可以将任意的容器抽象成一个序列,可以使用迭代器遍历容器中的元素
* 迭代器设计的目的是为了解决容器与算法之间的耦合问题,与指针类似,可以通过迭代器访问容器中的元素

* 迭代器的声明方式为:容器类型::iterator,比如:

std::vector<int>::iterator it;
std::list<int>::iterator it;
std::map<int, int>::iterator it;
std::set<int>::iterator it;

*/
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <list>

// 打印vector元素
void printVec(const std::vector<int> &v)
{
    std::cout << "[";
    for (const auto &e : v)
        std::cout << e << " ";
    std::cout << "]" << std::endl;
}

void test1()
{
    std::cout << "test1 ======================" << std::endl;
    std::vector<int> v1 {1, 2, 3, 4, 5};
    std::vector<int>::iterator it =  v1.begin(); // 指向第一个元素
    std::cout << *it << std::endl;

    it++; // 指向第二个元素
    std::cout << *it << std::endl;

    it += 2; // 指向第四个元素
    std::cout << *it << std::endl;

    it -= 2; // 指向第二个元素
    std::cout << *it << std::endl;

    it = v1.end() - 1; // 指向最后一个元素,注意end()指向最后一个元素的下一个位置
    std::cout << *it << std::endl;
    
}

void test2()
{
    std::cout << "test2 ======================" << std::endl;
    std::vector<int> v1 {1, 2, 3, 4, 5};
    auto it = v1.begin();

    while (it != v1.end())
    {
        std::cout << *it << std::endl;
        it++; // 指向下一个元素
    }

    it = v1.begin();
    while (it != v1.end())
    {
        *it = 100; // 修改元素值
        it++;
    }
    printVec(v1);

}

void test3()
{
    std::cout << "test3 ======================" << std::endl;
    std::vector<int> v1 {1, 2, 3, 4, 5};
    // std::vector<int>::const_iterator it = v1.begin(); // 常量迭代器,只能读取元素,不能修改元素
    auto it = v1.cbegin(); // 如果使用auto,需要使用cbegin()函数,返回一个常量迭代器

    while (it != v1.end())
    {
        std::cout << *it << std::endl;
        it++; // 指向下一个元素
    }

    it = v1.begin(); // 重新指向第一个元素
    while (it != v1.end())
    {
        // *it = 100; // 报错,不能修改元素
        it++; // 指向下一个元素
    }
    
}

void test4()
{
    std::cout << "test4 ======================" << std::endl;
    std::vector<int> v1 {1, 2, 3, 4, 5};
    auto it = v1.rbegin(); // 返回一个反向迭代器,指向最后一个元素
    while (it != v1.rend()) // rend()指向第一个元素的前一个位置
    {
        std::cout << *it << std::endl;
        it++; // 指向下一个元素
    }

    std::list<std::string> l1 {"hello", "world", "c++"};
    auto it2 = l1.rbegin();
    std::cout << *it2 << std::endl;
    it2++;
    std::cout << *it2 << std::endl;

    // map 里面的元素会自动按 key 进行排序
    std::map<std::string, std::string> m1 {
        {"hello", "你好"},
        {"world", "世界"},
        {"Computer", "计算机"}
    };

    auto it3 = m1.begin();

    while (it3 != m1.end())
    {
        std::cout << it3->first << " : " << it3->second << std::endl;
        it3++;
    }

}
int main()
{
    // test1();
    // test2();
    // test3();
    test4();
    return 0;
}

2、算法

  • STL算法基于迭代器生成的序列
  • STL提供了很多算法(例如查找、排序、计数、操作),可以对序列进行操作
  • 更多请查看:https://zh.cppreference.com/w/cpp/algorithm
  • 多数算法要求提供额外参数,例如:排序算法需要提供排序规则,一般使用函数指针、lambda表达式或仿函数(函数对象)

代码:

/*
* 算法示例
* STL算法基于迭代器生成的序列
* STL提供了很多算法(例如查找、排序、计数、操作),可以对序列进行操作
* 更多请查看:https://zh.cppreference.com/w/cpp/algorithm
* 多数算法要求提供额外参数,例如:排序算法需要提供排序规则,一般使用函数指针、lambda表达式或仿函数(函数对象)
*/

#include <iostream>
#include <vector>
#include <algorithm> // 算法头文件
#include <list>

void test1()
{
    std::cout << "test1 ======================" << std::endl;

    std::vector<int> v1{1, 2, 3, 4, 5};
    std::vector<int>::iterator loc = std::find(v1.begin(), v1.end(), 3); // 查找3
    std::cout << *loc << std::endl;  // 3
    std::cout << *v1.end() << std::endl; // 0
    if (loc != v1.end())
        std::cout << "找到 3" << std::endl;
    else
        std::cout << "未找到 3" << std::endl;
}

void test2()
{
    std::cout << "test2 ======================" << std::endl;
    std::vector<int> v1{1, 2, 3, 4, 5, 1, 2, 1};
    int counts = std::count(v1.begin(), v1.end(), 1); // 统计1的个数
    std::cout << "1的个数: " << counts << std::endl;
}

// 判断是否是偶数
bool isEven(int x)
{
    return x % 2 == 0;
}
void test3()
{
    std::cout << "test3 ======================" << std::endl;
    std::vector<int> v1{1, 2, 3, 4, 5, 6, 7, 8, 9};

    int counts = std::count_if(v1.begin(), v1.end(), isEven); // 使用函数指针统计偶数个数

    counts = std::count_if(v1.begin(), v1.end(), [](int x)
                           { return x % 2 == 0; }); // 使用lambda表达式统计偶数个数
    std::cout << "偶数个数: " << counts << std::endl;

    counts = std::count_if(v1.begin(), v1.end(), [](int x)
                           { return x > 6; }); // 统计大于6的个数
    std::cout << "大于6的个数: " << counts << std::endl;
}

void test4()
{
    std::cout << "test4 ======================" << std::endl;
    std::vector<int> v1{1, 2, 3, 4, 5, 1, 2, 1};
    for (const auto &e : v1)
        std::cout << e << " ";
    
    std::cout << std::endl;

    std::replace(v1.begin(), v1.end(), 1, 100); // 将1替换为100

    for (const auto &e : v1)
        std::cout << e << " ";
    std::cout << std::endl;
}

void test5()
{
    std::cout << "test5 ======================" << std::endl;
    std::vector<int> v1{1, 2, 3, 4, 5, 6, 7, 8, 9};
    if (std::all_of(v1.begin(), v1.end(), [](int x) { return x > 5; }) ) // 所有元素都大于5
        std::cout << "所有元素都大于5" << std::endl;
    else
        std::cout << "不是所有元素都大于5" << std::endl;
    
    if (std::any_of(v1.begin(), v1.end(), [](int x) { return x > 5; }) ) // 至少有一个元素大于5
        std::cout << "有元素大于5" << std::endl;
    else
        std::cout << "没有元素大于5" << std::endl;

    if (std::none_of(v1.begin(), v1.end(), [](int x) { return x < 0; }) ) // 没有元素小于0
        std::cout << "没有元素小于0" << std::endl;
    else
        std::cout << "有元素小于0" << std::endl;

}

void test6()
{
    std::cout << "test6 ======================" << std::endl;
    std::string s1 {"hello world"};
    std::cout << s1 << std::endl;
    std::transform(s1.begin(), s1.end(), s1.begin(), ::toupper); // 转换为大写,从s1的begin到end,转换后的结果放到s1的begin
    std::cout << s1 << std::endl;

}
int main()
{
    test1();
    // test2();
    // test3();
    // test4();
    // test5();
    // test6();

    return 0;
}

3、array容器示例

  • array大小固定,不可改变
  • 在内存中是连续的
  • 获取元素的复杂度是常数,与array元素个数无关
  • 是对原始数组的封装,也可以获取原始数组的指针
  • 如果数组大小固定,尽量使用array而不是使用C++原生数组因为array可以使用标准库的算法

代码:

/*
* array容器示例
* array大小固定,不可改变
* 在内存中是连续的
* 获取元素的复杂度是常数,与array元素个数无关
* 是对原始数组的封装,也可以获取原始数组的指针
* 如果数组大小固定,尽量使用array,而不是使用C++原生数组,因为array可以使用标准库的算法
*/

#include <iostream>
#include <array> // 使用array容器
#include <algorithm> 
#include <numeric> 

// 打印数组
void display(const std::array<int,5> &arr)
{
    std::cout << "[ ";
    for (const auto &a: arr)
        std::cout << a << " ";
    std::cout << "]" << std::endl;
}


void test1()
{
    std::cout << "test1 ======================" << std::endl;
    std::array<int, 5> arr1 {1, 2, 3, 4, 5};
    std::array<int, 5> arr2;

    display(arr1);
    display(arr2); // 未初始化,值为随机值

    arr2 = {10, 20, 30, 40, 50}; // 可以直接赋值

    display(arr1);
    display(arr2); 

    std::cout << "arr1的大小:" << arr1.size() << std::endl;
    std::cout << "arr2的大小:" << arr2.size() << std::endl;

    arr1[0] = 1000;
    arr1.at(1) = 2000;
    display(arr1);

    std::cout << "arr1的第一个元素:" << arr1.front() << std::endl;
    std::cout << "arr1的最后一个元素:" << arr1.back() << std::endl;
    
}

void test2()
{
    std::cout << "test2 ======================" << std::endl;
    std::array<int, 5> arr1 {1, 2, 3, 4, 5};
    std::array<int, 5> arr2 {10, 20, 30, 40, 50};

    display(arr1);
    display(arr2);

    arr1.fill(0);
    display(arr1);
    display(arr2);

    arr1.swap(arr2);
    display(arr1);
    display(arr2);

    
}

void test3()
{
    std::cout << "test3 ======================" << std::endl;
    std::array<int, 5> arr1 {1, 2, 3, 4, 5};
    int *ptr = arr1.data(); // 返回数组的首地址
    std::cout << ptr << std::endl;
    std::cout << *ptr << std::endl;
    *ptr = 1000;
    display(arr1);
}

void test4()
{
    std::cout << "test4 ======================" << std::endl;
    std::array<int, 5> arr1 {3,1,4,2,5};
    display(arr1);
    std::sort(arr1.begin(), arr1.end());
    display(arr1);
}

void test5()
{
    std::cout << "test5 ======================" << std::endl;
    std::array<int, 5> arr1 {3,6,4,2,5};
    std::array<int, 5>::iterator min_val = std::min_element(arr1.begin(), arr1.end());
    auto max_val = std::max_element(arr1.begin(), arr1.end());
    std::cout << "min: " << *min_val << std::endl;
    std::cout << "max: " << *max_val << std::endl;
}

void test6()
{
    std::cout << "test6 ======================" << std::endl;
    std::array<int, 5> arr1 {3,6,2,2,5};
    
    auto adjacent = std::adjacent_find(arr1.begin(), arr1.end()); // 查找相邻的两个相同的元素
    if (adjacent != arr1.end())
        std::cout << "adjacent: " << *adjacent << std::endl;
    else
        std::cout << "没有找到相邻的两个相同的元素" << std::endl;

}

void test7()
{
    std::cout << "test7 ======================" << std::endl;
    std::array<int, 5> arr1 {1,2,3,4,5};
    int sum = std::accumulate(arr1.begin(), arr1.end(), 0); // 求和
    std::cout << "sum: " << sum << std::endl;

}

void test8()
{
    std::cout << "test8 ======================" << std::endl;
    std::array<int, 10> arr1 {1,2,3,4,5,5,5,5,5,5};
    int counts = std::count(arr1.begin(), arr1.end(), 5); // 统计5的个数
    std::cout << "5一共出现了" << counts << "次" << std::endl;
}
int main()
{
    // test1();
    // test2();
    // test3();
    // test4();
    // test5();
    // test6();
    // test7();
    test8();
    return 0;
}

4、vector示例

  • vector是一个动态数组,可以随意增加元素
  • 与array一样,vector在内存中是连续的,对应的内存空间会随着元素的增加而增加
  • 获取元素的复杂度是常数,与vector的大小无关
  • 在vector末尾增加、删除元素的复杂度是常数,与vector的大小无关
  • 在vector中间增加、删除元素的复杂度是线性的,与vector的大小有关
  • 可以使用迭代器和算法

代码:

/*
* vector示例
* vector是一个动态数组,可以随意增加元素
* 与array一样,vector在内存中是连续的,对应的内存空间会随着元素的增加而增加
* 获取元素的复杂度是常数,与vector的大小无关
* 在vector末尾增加、删除元素的复杂度是常数,与vector的大小无关
* 在vector中间增加、删除元素的复杂度是线性的,与vector的大小有关
* 可以使用迭代器和算法
*/

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

// 打印vector的函数模板
template <typename T>
void printVector(const std::vector<T> &v)
{
    std::cout << "[";
    for (const auto &e : v)
        std::cout << e << " ";
    std::cout << "]" << std::endl;
}

void test1()
{
    std::cout << "test1 ======================" << std::endl;
    std::vector<int> v1{1, 2, 3, 4, 5};
    printVector(v1);

    v1 = {10, 20, 30, 40, 50}; // 可以直接赋值
    printVector(v1);

    std::vector<int> v2(10, 88); // 10个88
    printVector(v2);
}

void test2()
{
    std::cout << "test2 ======================" << std::endl;
    std::vector<int> v1{1, 2, 3, 4, 5};

    printVector(v1);
    std::cout << "size: " << v1.size() << std::endl;         // 大小
    std::cout << "capacity: " << v1.capacity() << std::endl; // 容量
    std::cout << "max_size: " << v1.max_size() << std::endl; // 最大容量

    v1.push_back(6); // 在尾部添加元素
    printVector(v1);
    std::cout << "size: " << v1.size() << std::endl;         // 大小
    std::cout << "capacity: " << v1.capacity() << std::endl; // 容量,每超出一次,容量翻倍
    std::cout << "max_size: " << v1.max_size() << std::endl; // 最大容量

    v1.shrink_to_fit(); // 释放多余的内存
    printVector(v1);
    std::cout << "size: " << v1.size() << std::endl;         // 大小
    std::cout << "capacity: " << v1.capacity() << std::endl; // 容量,释放多余的内存后,容量恢复到size大小
    std::cout << "max_size: " << v1.max_size() << std::endl; // 最大容量

    v1.reserve(100); // 预留100个元素的空间
    printVector(v1);
    std::cout << "size: " << v1.size() << std::endl;         // 大小
    std::cout << "capacity: " << v1.capacity() << std::endl; // 容量,预留100个元素的空间后,容量恢复到100,直到超出100
    std::cout << "max_size: " << v1.max_size() << std::endl; // 最大容量
}

void test3()
{
    std::cout << "test3 ======================" << std::endl;
    std::vector<int> v1{1, 2, 3, 4, 5};
    printVector(v1);
    v1[0] = 100;
    v1.at(1) = 200;
    printVector(v1);

    std::cout << "v1的第一个元素: " << v1.front() << std::endl;
    std::cout << "v1的最后一个元素: " << v1.back() << std::endl;

    v1.pop_back(); // 删除最后一个元素
    printVector(v1);
}

void test4()
{
    std::vector<int> v1{1, 2, 3, 4, 5};
    printVector(v1);

    v1.clear(); // 清空容器
    printVector(v1);

    v1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    printVector(v1);
    v1.erase(v1.begin(), v1.begin() + 3); // 删除前三个元素
    printVector(v1);

    // 删除所有偶数
    v1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    std::vector<int>::iterator it = v1.begin(); // 获取迭代器
    while (it != v1.end())
    {
        if (*it % 2 == 0)
            v1.erase(it);
        else
            it++;
    }
    printVector(v1);
}

void test5()
{
    std::cout << "test5 ======================" << std::endl;
    // 交换两个vector
    std::vector<int> v1{1, 2, 3, 4, 5};
    std::vector<int> v2{10, 20, 30, 40, 50};
    printVector(v1);
    printVector(v2);

    v1.swap(v2);
    printVector(v1);
    printVector(v2);
}

void test6()
{
    std::cout << "test6 ======================" << std::endl;
    std::vector<int> v1{9, 2, 5, 4, 7, 6, 8, 1, 3};
    printVector(v1);
    std::sort(v1.begin(), v1.end()); // 排序
    printVector(v1);
}

// 判断是否为偶数
int getEven(int x)
{
    return x % 2 == 0;
}

void test7()
{
    std::cout << "test7 ======================" << std::endl;
    std::vector<int> v1{1, 2, 3, 4, 5};
    std::vector<int> v2{10, 20};

    printVector(v1);
    printVector(v2);

    std::copy(v1.begin(), v1.end(), std::back_inserter(v2)); // 拷贝
    printVector(v1);
    printVector(v2);

    v1 = {1, 2, 3, 4, 5};
    v2 = {10, 20};
    // std::copy_if(v1.begin(),v1.end(),std::back_inserter(v2),getEven); // 拷贝偶数
    std::copy_if(v1.begin(), v1.end(), std::back_inserter(v2), [](int x)
                 { return x % 2 == 0; }); // 使用lambda表达式
    printVector(v1);
    printVector(v2);
}

void test8()
{
    std::cout << "test8 ======================" << std::endl;
    std::vector<int> v1{1, 2, 3, 4, 5};
    std::vector<int> v2{10, 20, 30, 40, 50};
    std::vector<int> v3;

    std::transform(v1.begin(), v1.end(), v2.begin(), std::back_inserter(v3),
                   [](int x, int y)
                   { return x + y; }); // 加法
    // std::transform(v1.begin(), v1.end(), v2.begin(), std::back_inserter(v3), std::plus<int>()); // 使用内置的加法函数
    std::cout << "v1 + v2 = " << std::endl;
    printVector(v3);

    v3.clear(); // 清空容器
    std::transform(v1.begin(), v1.end(), v2.begin(), std::back_inserter(v3),
                   [](int x, int y)
                   { return x * y; }); // 乘法
    // std::transform(v1.begin(), v1.end(), v2.begin(), std::back_inserter(v3), std::multiplies<int>()); // 使用内置的乘法函数
    std::cout << "v1 * v2 = " << std::endl;
    printVector(v3);
}

void test9()
{
    std::cout << "test9 ======================" << std::endl;
    std::vector<int> v1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    std::vector<int> v2{100, 200, 300, 400};
    printVector(v1);
    printVector(v2);

    auto it = std::find(v1.begin(), v1.end(), 5); // 查找5第一次出现的位置
    if (it != v1.end())
    {
        std::cout << "找到了:5 " << std::endl;
        v1.insert(it, v2.begin(), v2.end()); // 插入
    }
    else
    {
        std::cout << "没有找到" << std::endl;
    }

    printVector(v1);
}
int main()
{
    // test1();
    // test2();
    // test3();
    // test4();
    // test5();
    // test6();
    // test7();
    // test8();
    test9();
    return 0;
}

5、deque(double ended queue,双端数组)示例

  • 动态数组,和vector类似,但是deque是双端的,可以在头部和尾部进行插入和删除操作
  • 与vector不同,deque在内存中是分段连续的,每段内存都是连续的,所以在头部和尾部插入和删除元素都很快
  • 获取元素的复杂度是常数
  • 在头部和尾部插入和删除元素的复杂度是常数
  • 在中间插入和删除元素的复杂度是线性的
  • 支持迭代器和算法

代码:

/*
* deque(double ended queue,双端数组)示例
* 动态数组,和vector类似,但是deque是双端的,可以在头部和尾部进行插入和删除操作
* 与vector不同,deque在内存中是分段连续的,每段内存都是连续的,所以在头部和尾部插入和删除元素都很快
* 获取元素的复杂度是常数
* 在头部和尾部插入和删除元素的复杂度是常数
* 在中间插入和删除元素的复杂度是线性的
* 支持迭代器和算法
*/
#include <iostream>
#include <deque>
#include <vector>
#include <algorithm>

// 用于显示deque的函数模板
template <typename T>
void display(const std::deque<T> &d)
{
    std::cout << "[ ";
    for (const auto &item:d )
        std::cout << item << " ";
    std::cout << "]";
    std::cout << std::endl;
}

void test1()
{
    std::cout << "test1 ======================" << std::endl;
    std::deque<int> d1{1, 2, 3, 4, 5};
    display(d1);

    std::deque<int> d2 (10,100);
    display(d2);
    d2[0] = 99;
    d2.at(1) = 88;
    display(d2);
}

void test2()
{
    std::cout << "test2 ======================" << std::endl;
    std::deque<int> d1 {0,0,0,0};
    display(d1);

    d1.push_back(10);
    d1.push_back(20);
    display(d1);

    d1.push_front(100);
    d1.push_front(200);
    display(d1);

    std::cout << "第一个元素: " << d1.front() << std::endl;
    std::cout << "最后一个元素: " << d1.back() << std::endl;
    std::cout << "大小: " << d1.size() << std::endl;

    d1.pop_back();
    d1.pop_front();
    display(d1);
}

void test3()
{
    std::cout << "test3 ======================" << std::endl;
    std::vector<int> v1 {1,2,3,4,5,6,7,8,9,10};
    std::deque<int> d2;

    // 将vector中的偶数放入deque后,奇数放入deque前
    for (const auto &item:v1)
    {
        if (item % 2 == 0)
            d2.push_back(item);
        else
            d2.push_front(item);
    }
    display(d2);
}

void test4()
{
    std::cout << "test4 ======================" << std::endl;
    std::vector<int> v1 {1,2,3,4,5,6,7,8,9,10};
    std::deque<int> d2;

    // 将vector中的元素放到d2后
    for (const auto &item:v1)
        d2.push_back(item);
    display(d2);

    d2.clear(); // 清空deque
    // 将vector中的元素放到d2前
    for (const auto &item:v1)
        d2.push_front(item);
    display(d2);

    
}

void test5()
{
    std::cout << "test5 ======================" << std::endl;
    std::vector<int> v1 {1,2,3,4,5,6,7,8,9,10};
    std::deque<int> d2;

    // 使用std::copy实现test4效果
    std::copy(v1.begin(), v1.end(), std::back_inserter(d2));
    display(d2);
    
    d2.clear(); // 清空deque
    std::copy(v1.begin(), v1.end(), std::front_inserter(d2));
    display(d2);
}
int main()
{
    // test1();
    // test2();
    // test3();
    // test4();
    test5();
    return 0;
}

6、list(链表)容器

  • 动态大小
  • list是一个双向链表,支持快速的插入和删除操作
  • list不支持随机访问,不支持下标运算符

代码:

/*
* list(链表)容器
* 动态大小
* list是一个双向链表,支持快速的插入和删除操作
* list不支持随机访问,不支持下标运算符
*/

#include <iostream>
#include <list>
#include <algorithm>


// 打印list的函数模板
template <typename T>
void printList(const std::list<T> &l)
{
    std::cout << "[";
    for (const auto &e : l)
        std::cout << e << " ";
    std::cout << "]" << std::endl;
}

void test1()
{
    std::cout << "test1 ======================" << std::endl;
    std::list<int> l1 {1, 2, 3, 4, 5};
    printList(l1);

    std::list<std::string> l2;
    l2.push_back("hello");
    l2.push_back("world");
    printList(l2);

    std::list<int> l3;
    l3 = {1,2,3,4,5,6,7,8,9,10};
    printList(l3);

    std::list<int> l4 (10,88);
    printList(l4);


}

void test2()
{
    std::cout << "test2 ======================" << std::endl;
    std::list<int> l1 {1,2,3,4,5,6,7,8,9,10};
    printList(l1);

    std::cout << "第一个元素: " << l1.front() << std::endl;
    std::cout << "最后一个元素: " << l1.back() << std::endl;
    std::cout << "大小: " << l1.size() << std::endl;

    l1.clear();
    printList(l1);
    std::cout << "大小: " << l1.size() << std::endl;
}

void test3()
{
    std::cout << "test3 ======================" << std::endl;
    std::list<int> l1 {1,2,3,4,5,6,7,8,9,10};
    printList(l1);

    l1.resize(5); // 缩小到5个元素
    printList(l1);
}

void test4()
{
    std::cout << "test4 ======================" << std::endl;
    std::list<int> l1 {1,2,3,4,5,6,7,8,9,10};
    printList(l1);

    // 找到第一个5,然后在5前面追加一个100
    std::list<int>::iterator it = std::find(l1.begin(), l1.end(), 5);
    if (it != l1.end())
        l1.insert(it, 100);
    printList(l1);

    std::list<int> l2 {1000, 2000, 3000};
    // 将l2中的元素插入到l1中
    l1.insert(it, l2.begin(), l2.end());
    printList(l1);

    std::advance(it, -2); // it向前移动2个位置
    std::cout << *it << std::endl;

    l1.erase(it); // 删除it指向的元素,也就是2000
    printList(l1);
}

void test5()
{
    std::cout << "test5 ======================" << std::endl;
    std::list<int> l1 {3,5,2,10,7,9,8,1,4,6};
    printList(l1);
    l1.sort();
    printList(l1);
    
}
int main()
{
    // test1();
    // test2();
    // test3();
    // test4();
    test5();
    return 0;
}

7、set示例

  • set是一种关联式容器
  • 根据元素的值,自动排序,重复元素会被自动去重
  • 不支持随机访问,不支持下标运算符
  • 支持各种迭代器和算法

代码:

/*
* set示例
* set是一种关联式容器
* 根据元素的值,自动排序,重复元素会被自动去重
* 不支持随机访问,不支持下标运算符
* 支持各种迭代器和算法

*/
#include <iostream>
#include <set>

// 用于显示set的函数模板
template <typename T>
void printSet(const std::set<T> &s)
{
    std::cout << "[";
    for (const auto &e : s)
        std::cout << e << " ";
    std::cout << "]" << std::endl;
}

void test1()
{
    std::cout << "test1 ======================" << std::endl;
    std::set<int> s1{1, 2, 3, 4, 5};
    printSet(s1);

    s1 = {1,1,1,2,2,2,3,3,3}; // 重复元素会被自动去重
    printSet(s1);

    s1.insert(10); 
    s1.insert(0);
    printSet(s1);

    if (s1.count(10)) // count返回1表示找到,返回0表示未找到
        std::cout << "找到10" << std::endl;
    else
        std::cout << "未找到10" << std::endl;

    auto it = s1.find(10); // find返回迭代器,如果找到,返回迭代器指向该元素,否则返回end()
    if (it != s1.end())
        std::cout << "找到" << *it << std::endl;
    
    s1.clear();
    printSet(s1);
}

void test2()
{
    std::cout << "test2 ======================" << std::endl;
    std::set<std::string> s1 {"A", "B", "C", "D", "E"};
    printSet(s1);

    auto result = s1.insert("F"); // insert返回一个pair,第一个元素是迭代器,指向插入的元素,第二个元素是bool,表示是否插入成功
    printSet(s1);
    std::cout << std::boolalpha; // boolalpha表示输出true/false
    std::cout << "first: " << *(result.first) << std::endl;
    std::cout << "second: " << result.second << std::endl; // 插入成功,返回true


    result = s1.insert("A"); // A 已经存在,插入失败,但是返回的迭代器指向A
    printSet(s1);
    std::cout << std::boolalpha; // boolalpha表示输出true/false
    std::cout << "first: " << *(result.first) << std::endl;
    std::cout << "second: " << result.second << std::endl; // 插入失败,返回false,表示有重复元素

}

int main()
{
    // test1();
    test2();
    return 0;
}

8、map示例

  • map是一种关联式容器,它的元素是key-value对(std::pair),key是唯一的,value可以重复
  • map中的元素是按key自动排序的
  • 使用key访问元素

代码:

/*
* map示例
* map是一种关联式容器,它的元素是key-value对(std::pair),key是唯一的,value可以重复
* map中的元素是按key自动排序的
* 使用key访问元素

*/

#include <iostream>
#include <map>
#include <set>

// 打印map的函数模板
template <typename T1, typename T2>
void printMap(const std::map<T1, T2> &m)
{
    std::cout << "[";
    for (const auto &e : m)
        std::cout << e.first << ":" << e.second << " ";
    std::cout << "]" << std::endl;
}

// map的value是set
void printMap(const std::map<std::string, std::set<int>> &m)
{
    std::cout << "[";
    for (const auto &e : m)
    {
        std::cout << e.first << ":[ ";
        for (const auto &s : e.second)
            std::cout << s << " ";
        std::cout << "] ";
    }
    std::cout << "]" << std::endl;
}

void test1()
{
    std::cout << "test1 ======================" << std::endl;
    std::map<std::string, int> m1 { // string是key,int是value
        {"mike", 10},
        {"jane", 20},
        {"tom", 30},
    };
    printMap(m1); // [jane:20 mike:10 tom:30 ],会自动按key排序

    m1.insert(std::pair<std::string, int>("anna", 100)); // 插入一个pair
    printMap(m1); 

    m1.insert(std::make_pair("bob", 200)); // 插入一个pair
    printMap(m1);

    m1["jim"] = 300; // 如果key不存在,会自动插入一个pair,如果key存在,会更新value
    printMap(m1);
    m1["jim"] += 100; // 更新value
    printMap(m1);

    std::cout << "mike的计次:" << m1.count("mike") << std::endl; // count返回1表示找到,返回0表示未找到
    std::cout << "alice的计次:" << m1.count("alice") << std::endl; 

    auto it = m1.find("jim"); // find返回迭代器,如果未找到,返回end()
    if (it != m1.end())
        std::cout << "找到" << it->first << ",value为" << it->second << std::endl;
    else
        std::cout << "未找到jim" << std::endl;

    m1.clear(); // 清空map
    printMap(m1);

}

void test2()
{
    std::cout << "test2 ======================" << std::endl;
    std::map<std::string, std::set<int>> student_grades { // string是key,set是value
        {"mike", {100, 90}},
        {"jane", {99, 88, 77}},
        {"tom", {98, 87, 76}},
    };

    printMap(student_grades);

    student_grades["mike"].insert(80); // 插入80分
    printMap(student_grades);

    auto it = student_grades.find("jane");
    if (it != student_grades.end())
    {
        it->second.erase(88); // 删除88分
        printMap(student_grades);
    }
   
}

int main()
{
    // test1();
    test2();
    return 0;
}

9、stack 示例

  • stack 是一种容器适配器,遵循后进先出(LIFO)的原则
  • stack 本身不是容器,它是基于容器实现的(如vector、list、deque等)
  • 所有的操作都在栈顶进行(top)
  • stack 本身没有迭代器

代码:

/*
* stack 示例
* stack 是一种容器适配器,遵循后进先出(LIFO)的原则
* stack 本身不是容器,它是基于容器实现的(如vector、list、deque等)
* 所有的操作都在栈顶进行(top)
* stack 本身没有迭代器
*/

#include <iostream>
#include <stack>
#include <vector>
#include <list>
#include <deque>


// 显示stack的函数模板
template <typename T>
void display(std::stack<T> s)
{
    std::cout << "[";
    while (!s.empty())
    {
        T elem = s.top(); // 读取栈顶元素
        std::cout << elem << " ";
        s.pop(); // 弹出栈顶元素
    }
    std::cout << "]" << std::endl;
}
int main()
{
    std::stack<int> s;

    for (auto i: {1,2,3,4,5})
        s.push(i);
    display(s);

    s.push(100); // 压入元素
    display(s);

    s.pop(); // 弹出元素
    s.pop();

    display(s);

    // s.clear(); // 并没有clear()方法
    while (!s.empty())
        s.pop(); // 弹出所有元素
    display(s);

    s.push(10);
    display(s);

    s.top() = 100; // 修改栈顶元素
    display(s);

    return 0;
}

10、queue示例

  • queue是一种容器适配器,遵循先进先出(FIFO)的原则
  • queue的底层容器可以是deque、list
  • 元素只能从队尾压入,从队首弹出(排队)
  • queue本身没有提供迭代器

代码:

/*
* queue示例
* queue是一种容器适配器,遵循先进先出(FIFO)的原则
* queue的底层容器可以是deque、list
* 元素只能从队尾压入,从队首弹出(排队)
* queue本身没有提供迭代器
*/

#include <iostream>
#include <queue>

// 显示queue的函数模板
template <typename T>
void display(std::queue<T> q)
{
    std::cout << "[";
    while (!q.empty())
    {
        T elem = q.front(); // 读取队首元素
        std::cout << elem << " ";
        q.pop(); // 弹出队首元素
    }
    std::cout << "]" << std::endl;
}

int main()
{
    std::queue<int> q;
    for (auto i : {1, 2, 3, 4, 5})
        q.push(i);
    display(q);

    std::cout << "队首元素: " << q.front() << std::endl;
    std::cout << "队尾元素: " << q.back() << std::endl;

    q.push(100); // 压入元素
    display(q);

    q.pop(); // 弹出元素
    q.pop();

    display(q);

    // q.clear(); // 并没有clear()方法
    while (!q.empty())
        q.pop(); // 弹出所有元素
    display(q);

    std::cout << "size: " << q.size() << std::endl;

    q.push(10);
    q.push(20);
    q.push(30);
    display(q);

    std::cout << "第一个元素: " << q.front() << std::endl;
    std::cout << "最后一个元素: " << q.back() << std::endl;

    q.front() = 100; // 修改队首元素
    q.back() = 200; // 修改队尾元素
    display(q);

    return 0;
}

11、priority_queue (优先级队列)示例

  • 允许按照优先级来插入和删除元素
  • 优先级最高的元素总是位于队首(最大值在队首)
  • 本身没有提供迭代器

代码:文章来源地址https://www.toymoban.com/news/detail-740977.html

/*
* priority_queue (优先级队列)示例
* 允许按照优先级来插入和删除元素
* 优先级最高的元素总是位于队首(最大值在队首)
* 本身没有提供迭代器

*/
#include <iostream>
#include <queue>

// 显示priority_queue的函数模板
template <typename T>
void display(std::priority_queue<T> pq)
{
    std::cout << "[";
    while (!pq.empty())
    {
        T elem = pq.top(); // 读取优先级最高元素
        std::cout << elem << " ";
        pq.pop(); // 弹出优先级最高元素
    }
    std::cout << "]" << std::endl;
}

void test1()
{
    std::cout << "test1 ======================" << std::endl;
    std::priority_queue<int> pq;
    for (auto i : {3,5,8,1,2,9,4,7,6})
        pq.push(i);
    display(pq);

    std::cout << "大小: " << pq.size() << std::endl;
    std::cout << "最大值: " << pq.top() << std::endl;

    pq.pop(); // 弹出最大值
    display(pq);
}

int main()
{
    test1();
    return 0;
}

到了这里,关于C++进阶语法——STL 标准模板库(下)(Standard Template Library)【学习笔记(七)】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】:STL——标准模板库介绍 || string类

    STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且 是一个包罗数据结构与算法的软件框架 原始版本 Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本,本着开源精神,他们声明允许任何人任意运用、拷贝、修改、传播、商

    2024年02月05日
    浏览(55)
  • c++标准模板(STL)(std::array)(三)

    template     class T,     std::size_t N struct array; (C++11 起   std::array 是封装固定大小数组的容器。 此容器是一个聚合类型,其语义等同于保有一个 C 风格数组 T[N] 作为其唯一非静态数据成员的结构体。不同于 C 风格数组,它不会自动退化成 T* 。它能作为聚合类型聚合初始化,只要

    2024年02月02日
    浏览(47)
  • C++——STL标准模板库——容器详解——list

    list:双向链表。list是一种分布式存储的线性表,每个节点分为数据域和指针域,其中指针域中包含一个指向前驱节点的指针和一个指向后续节点的指针,基本模型如下: 1、双向链表:每个元素都有一个前驱和一个后继,这种结构允许在链表的任何位置实现快速的插入和删除

    2024年01月16日
    浏览(46)
  • c++ 11标准模板(STL) std::vector (二)

    template     class T,     class Allocator = std::allocatorT class vector; (1) namespace pmr {     template class T     using vector = std::vectorT, std::pmr::polymorphic_allocatorT; } (2) (C++17 起) 1) std::vector 是封装动态数组的顺序容器。 2) std::pmr::vector 是使用多态分配器的模板别名。 元素相继存储,这意味着不

    2024年02月02日
    浏览(53)
  • (AI创作实验)C++中的STL(标准模板库)

    STL概述 STL: (Standard Template Library) 标准模板库 包含一些常用的算法如排序查找,还有常用的数据结构如可变长数组、链表、字典等。 使用方便,效率较高 要使用其中的算法,需要#include C++中的STL(标准模板库)是一个非常强大的工具,为程序员提供了许多高效的数据结构和算

    2023年04月18日
    浏览(46)
  • C++标准模板(STL)- 类型支持 (数值极限,C 数值极限接口)

    参阅 std::numeric_limits 接口 定义于头文件 cstdint PTRDIFF_MIN (C++11) std::ptrdiff_t 类型对象的最小值 (宏常量) PTRDIFF_MAX (C++11) std::ptrdiff_t 类型对象的最大值 (宏常量) SIZE_MAX (C++11) std::size_t 类型对象的最大值 (宏常量) SIG_ATOMIC_MIN (C++11) std::sig_atomic_t 类型对象的最小值 (宏常量) SIG_ATOMIC_

    2024年02月07日
    浏览(40)
  • C++、STL标准模板库和泛型编程 ——适配器、补充(侯捷)

    侯捷 C++八部曲笔记汇总 - - - 持续更新 ! ! ! 一、C++ 面向对象高级开发 1、C++面向对象高级编程(上) 2、C++面向对象高级编程(下) 二、STL 标准库和泛型编程 1、分配器、序列式容器 2、关联式容器 3、迭代器、 算法、仿函数 4、适配器、补充 三、C++ 设计模式 四、C++ 新标准 五、

    2023年04月27日
    浏览(70)
  • C++、STL标准模板库和泛型编程 ——迭代器、 算法、仿函数(侯捷)

    侯捷 C++八部曲笔记汇总 - - - 持续更新 ! ! ! 一、C++ 面向对象高级开发 1、C++面向对象高级编程(上) 2、C++面向对象高级编程(下) 二、STL 标准库和泛型编程 1、分配器、序列式容器 2、关联式容器 3、迭代器、 算法、仿函数 4、适配器、补充 三、C++ 设计模式 四、C++ 新标准 五、

    2023年04月25日
    浏览(51)
  • 0829|C++day7 auto、lambda、C++数据类型转换、C++标准模板库(STL)、list、文件操作

        封装一个学生的类,定义一个学生这样类的vector容器, 里面存放学生对象(至少3个) 再把该容器中的对象,保存到文件中。 再把这些学生从文件中读取出来,放入另一个容器中并且遍历输出该容器里的学生。

    2024年02月10日
    浏览(44)
  • C++标准模板(STL)- 类型支持 (类型特性,is_union,is_class,is_function)

    类型特性定义一个编译时基于模板的结构,以查询或修改类型的属性。 试图特化定义于 type_traits 头文件的模板导致未定义行为,除了 std::common_type 可依照其所描述特化。 定义于type_traits头文件的模板可以用不完整类型实例化,除非另外有指定,尽管通常禁止以不完整类型实

    2024年02月06日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包