C++ STL库详解

第零章 我们为什么要学STL库?

STL库(英文全称:Standard Template Library,标准模板库),STL库提供了很多模板以供用户使用,从而精简代码,以提升代码的可读性。

以快速排序为例:

不使用STL库的代码如下:

void quickSort(int arr[], int low, int high) {
    if (low < high) {
        int i = low, j = high;
        int pivot = arr[low]; // 基准元素
        while (i < j) {
            while (i < j && arr[j] >= pivot) j--;
            if (i < j) arr[i++] = arr[j];
            while (i < j && arr[i] <= pivot) i++;
            if (i < j) arr[j--] = arr[i];
        }
    arr[i] = pivot;
    quickSort(arr, low, i - 1); // 递归排序左子数组
    quickSort(arr, i + 1, high); // 递归排序右子数组
}

看起来是不是超级复杂?但是!!!使用STL库的话,就能把代码简写成这样了:

sort(arr.begin(),arr.end());

一行就搞定了!

这就是STL库的魅力!那么,接下来让我们进入STL的奇妙世界吧!

第一章 vector

1.1 vector是什么

vector是一个数组,和C风格的数组int arr[]不同的是,它会动态分配内存空间,以达到最大化利用内存空间的效果。

如:在算法竞赛中有时候会遇到需要开辟一个1≤m,n≤106,1≤m×n≤106的二维数组的场景,这个时候用 int arr[100010][100010]会导致栈空间严重浪费(MLE),而使用vector数组就不会出现这种问题(vector<vector<int>> arr(m+10,vector<int> (n+10))

另外,vector数据存储在堆上,因此不会发生栈空间溢出的情况,但需注意:在构造二维vector对象的时候,因为vector对象本身的信息仍在栈上,仍有可能发生栈溢出。

1.2 如何构造一个vector对象

vector创建对象的基本形式:

vector<数据类型> 函数名;

vector对象的函数构造有以下几种形式:

    vector<int> v1; //创建一个空的vector对象
    vector<int> v2(a); //创建一个长度为a的vector对象,默认全部赋值为0
    vector<int> v3(a,b); //创建一个长度为a的vector对象,并全部赋值为b
    //另外,还有以下几种进阶形式
    vector<vector<int> > v4(a,vector<int>(b)) //创建一个长为a、宽为b的二维vector对象
    vector<vector<int> > v5(a,vector<int>(b,c)) //创建一个长为a、宽为b的二维vector对象,并全部赋值为c

1.3 vector对象的操作

以下所写代码已默认创建了vector对象

vector<int> vec;

1.3.1 push_back()

基本格式:vec.push_back(a);

用法讲解:用于在vector数组的尾部插入一个数a

时间复杂度: O ( 1 ) O(1) O(1)

1.3.2 pop_back()

基本格式:vec.pop_back();

用法讲解:删除vector的尾部元素

时间复杂度: O ( 1 ) O(1) O(1)

1.3.3 begin()和end()

基本格式:vec.begin()vec.end()

用法讲解:begin()返回值为第一个元素的地址,end()返回值为最后一个元素的下一个区域的地址

1.3.4 insert()

基本格式:

  1. vec.insert(pos,value)(pos为地址,value为值)

  2. vec.insert(pos,count,value)(pos为地址,count和value为值)

  3. vec.insert(pos,first,last)(pos、first、last均为地址)

用法讲解:

  1. 从pos处插入元素value

  2. 从pos处插入count个元素value

  3. 从pos处插入从first到last的元素(左闭右开)

举例

#include<vector>
#include<iostream>

int main()
{
    std::vector<int> vec1;
    std::vector<int> vec2;

    for(int i=0;i<10;i++)
    {
        vec1.push_back(i+1);
    }
    for(int i=0;i<10;i++)
    {
        vec2.push_back(i+1);
    }
    vec1.insert(vec1.begin()+1,11);
    vec1.insert(vec1.begin()+3,12);
    vec1.insert(vec1.begin(),5,13);
    vec1.insert(vec1.begin(),vec2.begin(),vec2.end());
    for(int i=0;i<vec1.size();i++)
    {
        std::cout << vec1[i] << ' ';
    }
    return 0;
}

它的运行结果为

1 2 3 4 5 6 7 8 9 10 13 13 13 13 13 1 11 2 12 3 4 5 6 7 8 9 10

代码分析:
首先,vec1和vec2都是从1到10这10个元素
然后,向vec1的第1个元素和第2个元素之间插入11
再然后,向vec1的第3个元素和第4个元素之间插入12
接着,向vec1的最前面插入5个13
最后,向 vec1的最前面依次插入vec2的所有元素
时间复杂度: O ( n ) O(n) O(n)

1.3.5 erase()

基本格式:

  1. vec.erase(pos)
  2. vec.erase(first, last)

用法讲解:

  1. 删除pos处的值
  2. 删除从first到last之间的值(左闭右开)

时间复杂度: O ( n ) O(n) O(n)

1.3.6 resize()

基本格式:vec.resize(n,value)
用法讲解:修改vector的长度。如果是缩短,则删除多余的值;如果是扩大,且指定了默认值,则新元素均为默认值value(旧元素不变)
时间复杂度: O ( n ) O(n) O(n)

1.3.7 clear()

基本格式:vec.clear()
用法讲解:清空vec中的所有元素
时间复杂度: O ( n ) O(n) O(n)

1.3.8 empty()

基本格式:vec.empty()
用法讲解:如果vec里面是空的,返回true,否则返回false
时间复杂度: O ( 1 ) O(1) O(1)

第二章 stack

栈(Stack)是一个后入先出的数据结构(LIFO),STL库提供了封装好的模拟栈的数据结构

2.1 创建栈

栈的封装在<stack>头文件上,创建栈的代码如下:

#include<stack>

int main()
{
    std::stack<int> stk;
}

格式如下:

stack<数据类型> 栈名

2.2 栈的操作

2.2.1 push()

push()用于向栈顶推入元素

例如:stk.push(1); stk.push(2);

2.2.2 pop()

pop()用于移除栈顶元素

用法:stk.pop();

2.2.3 top()

功能:查看栈顶元素

用法:

#include<stack>
#include<iostream>

int main()
{
    std::stack<int> stk;
    stk.push(1); //推入1
    stk.push(2); //推入2
    std::cout << "Top element: "<< stk.top() << std::endl; //输出2
    stk.pop(); //移除2
    std::cout << "Top element after pop: "<< stk.top() << std::endl; //此时栈顶元素为1,所以输出1
    return 0;
}

2.2.4 empty()

功能:查询栈是否为空,如果栈为空,返回true,否则返回false

用法:

#include<stack>

int main()
{
    std::stack<int> stk;
    stk.push(1); //推入1
    stk.push(2); //推入2
    stk.pop(); //移除2
    if(stk.empty())
    {
        // Do something ...
        // 这里的代码实际上并不会被执行,因为此时栈仍有一个元素,stk.empty()返回false
    }
    stk.pop();
    if(stk.empty())
    {
        // Do something ...
        //这里的代码会被执行,因为此时栈为空,stk.empty()返回true
    }
    return 0;
}

2.2.5 size()

功能:返回栈内元素的个数

用法:略。

2.3 其它的注意事项

stack只能入栈、出栈和访问栈顶元素,不能做其他的事情,比如int a = stk[1];这种是不被允许的。

第三章 queue和priority_queue

3.1 队列

队列是一个先入先出的数据结构,它的push()pop()操作和栈一样,这里不再赘述。

队列包含在头文件<queue>

最主要的是队列没有top(),取而代之的是front(),也就是返回队首元素。

3.2 优先队列

优先队列与队列不同的是,优先队列会自动对队列元素进行排序,且默认为大顶堆(即最大的元素排在队首)

下面看一段代码示例:

#include<queue>
#include<iostream>

int main()
{
    std::priority_queue<int> pq;
    pq.push(1); //把1推入pq
    pq.push(3); //把3推入pq,3>1,所以3在前面
    pq.push(2); //把2推入pq,2<3,所以2在3后面,在1前面
    std::cout << pq.top() << std::endl; //输出最大的元素3
    return 0;
}

第四章 算法库<algorithm>

4.1 swap(a,b)

用法介绍:交换两个变量的值

代码示例:

#include<algorithm>
#include<iostream>

int main()
{
    int a = 10, b = 20;
    std::swap(a,b); //交换a和b的值
    std::cout << a << ' ' << b; //输出20 10
}

4.2 sort(arr.begin(),arr.end())

用法介绍:快速排序数组(原地排序)

代码示例:

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

int main()
{
    std::vector<int> vec={4,2,3,1,5}; //此时vec里面的元素顺序为[4,2,3,1,5]
    std::sort(vec.begin(),vec.end()); //按照从小到大的顺序将vec进行排序
    for(int i=0;i<5;i++)
    {
        std::cout << vec[i] << " "; //输出结果1 2 3 4 5
    }
    return 0;
}

进阶用法介绍:

sort(arr.begin(),arr.end(),greater<int>); //从大到小进行排序

时间复杂度: O ( n log ⁡ n ) O(n\log n) O(nlogn)sort内置算法为快速排序算法)

4.3 __gcd(a,b)和__lcm(a,b)

功能介绍:__gcd(a,b)求最大公约数,__lcm(a,b)求最小公倍数

代码示例:

#include<algorithm>
#include<iostream>

int main()
{
    int a=3, b=8;
    std::cout <<"gcd(a,b)= " << std::__gcd(a,b);
    return 0;
}

(因为lcm函数C++11标准好像不支持,所以此处最好还是手写一个lcm函数)

lcm(最小公倍数)函数实现如下所示:

#include<algorithm>

int lcm(int a,int b)
{
    return a*b/std::__gcd(a,b);
}

后记

由于作者本人能力有限,无法详尽地写出所有的STL库的用法,本篇文章仅提供算法竞赛中常用的STL库用法的讲解

本篇文章所述代码均为C++11标准下的代码,且并未使用全局声明命名空间std(using namespace std;)和万能头文件(bits/stdc++.h),但在算法竞赛中一般可以使用,请读者自行选择是否使用。

posted @ 2025-05-22 17:18  Tianshang301  阅读(138)  评论(0)    收藏  举报  来源