算法竞赛中常用的容器(C++)
本文最后更新于44 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com

前言:

在算法竞赛中,如果要用到例如 队列,栈 等数据结构类型时,不用自己构造,在C++中已将封装好了多种容器,只需引用头文件就可以进行使用,极大的提高了编写效率。

1. vector:

#include <iostream>
#include <vector>     //对应头文件
using namespace std;
//语法 :  vector<类型> arr(长度,[初值])
void print_str(char a[]){
    cout << a[0] << endl;
}

int main(){
    vector<int> arr; //创建整型数组 arr,如果没有定义长度,则默认长度为0;
    vector<int> arr1(10, 0);//创建长度为10的整形数组,初值为0
    //类比,我们可以定义不同的类型数组
    vector<double> arr3(10, 2);
    vector<char> arr4(10, '*');
    //二维数组
    vector<vector<int>> arr_2(5, vector<int>(5, 0));
    //构造初始5行,初始5列的二维数组,初值为0;


    //尾插:
    arr.push_back(1);
    arr.push_back(2);
    arr.push_back(3);//此时arr的长度已经变成了3
    
    //尾删

    arr.pop_back();
    arr.pop_back();//此时arr的长度为1;

    //获取数组长度 
    cout << arr.size() << endl; // size = 1;

    //清空数组
    arr.clear();

    //判断数组是否为空, 返回的是布尔值
    cout << arr.empty() << endl; //空值返回1

    
    //改变数组的长度
    arr.resize(5, 10);//将arr数组长度改为5,且对新加入的数值初始化为10;

    //迭代器遍历
    for(auto x : arr){
        cout << x << endl;
    }
}

2. priority_queue<>优先队列:

using namespace std;

//对于有大量元素且需要排序时可以使用, 边插入边排序
int main(){
    //优先队列,默认为大顶堆
    priority_queue<int> pque;
    pque.push(1);
    pque.push(3);
    pque.push(4);
    pque.push(2);
    cout << pque.top() << endl;//堆区的最大值

    pque.pop();
    pque.pop();//移除队列的第一项 
    cout << pque.top() << endl;

    //小顶堆
    priority_queue<int, vector<int>, greater<int>> pque_small;
    pque_small.push(6);
    pque_small.push(4);
    pque_small.push(5);
    cout << pque_small.top() << endl;//小顶堆,为4
}
/*
注意:
    1.仅堆顶可读:只可访问堆顶,其他元素都不可读到
    错误用法:
    cout << pque[1] << endl;  

    2.所有元素都是不可写:堆中的所有元素都是不可修改的
    错误用法:
    pque[1] = 2;
    pque.top() = 1;   
    
*/

3.set集合

#include <iostream>
#include <set>
using namespace std;
int main(){
    //set 有确定性 互异性 从小到大排序 
    //
    set<int> st;                //储存int类型(从大到小)
    set<int, greater<int>> st2; //储存int的集合(从小到大)
    st.insert(2);
    st.insert(4);
    st.insert(2);
    st.insert(3);

    //查找find 返回的是迭代器,如果找不到返回尾迭代器
    if(st.find(2) != st.end()){
        cout << "Yes" << endl;
    }
    //查找count 返回该元素在集合set中的个数,如果找不到则返回0
    //对于普通函数,该函数仅有0和1两个返回值,但对于multiset(无互异性)的来说,count返回该元素在集合中的个数
    if(st.count(2) == 1){
        cout << "Yes" << endl;
    }


    //可使用迭代器进行遍历
    for(auto &ele : st){
        cout << ele << endl;
    }
    //删除元素
    st.erase(2);
    cout << " " << endl;
    //大小:
    cout << st.size() << endl;

    //清空 clear
    st.clear();

    //判空
    cout << st.empty() << endl;

    //使用迭代器进行遍历
    for(auto &ele : st){
        cout << ele << endl;
    }

    for(set<int>::iterator it = st.begin(); it != st.end(); ++it){
        cout << *it << endl;
    }
    /*适用情形:
        元素去重
        维护顺序
        元素是否出现过,当所存储的数据较多时(-10^18 -- 10^18),vis数组无法完成,就可以使用set数组完成
    */

    
    //注意:
    //set的迭代器取到的元素是只读的,不可修改,要想修改,需要先erase,再insert
    //set元素虽然可以遍历,但是仅可使用迭代器进行遍历,不存在下标这一概念,无法使用下标进行访问
    

}

4.pair二元组

#include <utility>

#include <iostream>

using namespace std;

//二元组pair :就是用来存储二元组的

/*

pair<第一个值的类型, 第二个值的类型> = {第一个值, 第二个值};

*/

int main(){

pair<int, int> p1 = {1, 2};

pair<char, int> p2 = {'a', 2};

cout << p1.first << " " << p1.second << endl; //输出 1 2

cout << p2.first << " " << p2.second << endl; //输出 a 2

//pair可以判断是否相等

if(p1 == p2){

cout << "Yes" << endl;

}else{

cout << "No" << endl;

}

//二元组可以嵌套,但是套的太多就抽搐了🤔

pair<int, pair<int, int>> p3;

}

5. map图

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

//提供对数时间的有序键值对结构,底层原理是红黑树
//映射
/*
    结构:
    map<键类型,值类型,比较器(默认可以不写)>
    键类型:要储存键的数据类型
    值类型:要储存值的数据类型
    比较器:键比较大小使用的比较器, 默认为less<类型>,可自定义
*/
int main(){
    map<int, int> mp1;                  // int -> int 的映射(从小到大)
    map<int, int, greater<int>> mp2;    // int -> int 的映射(从大到小)

    map<string, int> st1;               // string -> int 的映射
    map<int, vector<int>> ve;           // int -> vector 的映射

    //增
    mp1[2] = 2;                         // 2 -> 1
    mp1[1] = 1;                         // 1 -> 2

    //find()查找 返回找到元素的迭代器, 注意是对 键 的查找
    if(mp1.find(2) != mp1.end()){
        cout << "yes" << endl;          // yes
    }

    //count() 统计map中键值出现的个数
    cout << mp1.count(1) << endl;       // 输出 1
    cout << mp1.count(3) << endl;       // 输出 0
    /*注意:对于map来说,即使没有给赋map值,但是该键已经存在,如下行代码:
        mp1[3];       
        虽然没有给她赋值,但是map中还是存在该键 3 ,且初始值为 0 
        即:
        cout << mp1.count << endl;      // 输出 1 


        if(mp1.find(3) != mp1.end()){
            cout << "yes" << endl;      // yes
        }
    */
    
    //大小
    cout << mp1.size() << endl;         //输出 2
    
    //清除
    mp1.clear();

    //判空
    cout << mp1.empty() << endl;        // 输出 1   


    mp1[2] = 2;                        
    mp1[1] = 1;
    mp1[999] = 7894;

    //迭代器, 迭代到map的值为结构题, frist对应键, second对应值
    for(map<int, int>::iterator it = mp1.begin(); it != mp1.end(); ++it){
        cout << it->first << " " << it->second << endl;
    }
    /*  输出:
        1 2
        1 1
        999 7894
    */

    for(auto &pr : mp1){
        cout << pr.first << " " << pr.second << endl;
    }
    //输出结果同上;

    /*
        适用情况:
        -例如统计每个字符串或字符出现的次数(map<string, int>)
    */
    


}

6.string字符串

这是我认为最有用库,没学这个之前面对字符串时我都在干什么?

#include <iostream>
#include <cstring> //等效于下面写法
//#include <string.h>

using namespace std;
//c++的结构体中允许存在函数
struct MM{
    int age;
    void print(){
        cout << age << endl;
    }
};

int main(){
    //如何访问函数
    MM mm;
    mm.age = 11;
    //mm.print();
//1, string的创建方式
    string str1  = "str1"; //构造函数
    string str2;
    str2 = "str2";// 与上方不一样,调用拷贝构造函数

    string str3("str3");

    //了解
    string str4(4, 'x'); //用4个x初始化字符串;
    //下标从0开始 
    string str5("ILoveYou", 1, 4); //用字符串的从下标1开始的4位初始化str5;
    cout << str5 << endl;

//2, C++string与c语言char* 的区别
    
    //c++中没有'/0';
    str2 = "HelloWorld";
    char array[] = "HelloWorld";
    cout << str2.size() << endl;
    cout << str2.length() << endl;
    //不可以使用printf()
    //printf("%s", str2);
    
    //c++ string为我们提供了一个访问字符串的接口:.data(), .str()
    //使用这两个函数才能实现对字符串的访问
    printf("%s\t%s\n", str2.data(), str2.c_str());

//3 .string的基本操作
    //赋值删改查
    //3.1 c++的赋值方式 通过函数赋值 assign
    string s1("IMissYou");
    string s2;        //string s2(s1);
    s2.assign(s1);    //s2=s1;
    cout << s2 << endl;

    s2.assign(s1, 1, 4);//用字符串的从下标1开始的4位初始化s2;
    cout << s2 <<endl;

    s2.assign(4, 'K');
    cout << s2 <<endl;
    //3.2 比较 c++ string和c语言string比较规则是一样的
    //”123“ ”13“, 后者大
    string frist = "123";
    string second = "12";
    cout << (frist > second) << endl;
    cout << (frist != second) << endl;
    cout << (frist < second) << endl;
    
    cout << frist.compare(second) << endl;
    //3.3字符串的链接操作
    frist = frist + second;
    cout << frist << endl;
    //使用函数进行链接
    frist.append(second, 0 ,1);
    cout << frist << endl;

    //3.4查找函数
    /*
        返回的是string::npos        等于-1;
        find :从左往右找字符串或字符出现的位置;
        rfind:从后往前找
    */
    string str6 = "abcdefghijklmn";
    if(str6.find("efg") != string::npos){
        cout << str6.find("efg") << endl;
    }//返回查找到的下标

    //3.5 替换 replace
    string str7 ("Helloworld");
    str7.replace(1, 4, 4, 'o');
    cout << str7 << endl;   
    //3.6 删除字符串 erase;
    string str8 = "Helloworld";
    str8.erase(1, 4);
    str8.erase(1); //删掉下标1以后的所有内容
    
    cout << str8 << endl;

}

7.迭代器

这东西还是不用为好

// 为什么要选择迭代器?
/*
    很多数据结构并不是线性的(例如红黑树), 对于非线形的数据结构,下表是没有意义的,无法使用下标来遍历整个数据结构
    迭代器的作用就是定义某个数据结构的遍历方式, 通过迭代器的增减,代表遍历到的位置,通过迭代器就能成功遍历非线性结构了
    例如set的实现是红黑树, 我们没有办法用下标来访问元素的,但是通过迭代器就可以实现
*/
    set<int> b;
    for(set<int>::iterator it = b.begin(); it != b.end(); ++it){
        cout << *it << endl;
    }

//迭代器用法
/*
    对于vector容器,它的迭代器功能比较完整,以它为例
        .begin()        头迭代器
        .end()          尾迭代器 
        .rbegin()       反向头迭代器
        .rend()         反向尾迭代器
        迭代器 + 整型     将迭代器向后移动
        迭代器 - 整型     将迭代器向前移动
        迭代器++         将迭代器向后移动1位
        迭代器--         将迭代器向前移动1位
        迭代器-迭代器     两个迭代器的距离
        pre(it)         返回it的前一个迭代器
        next(it)        返回it的后一个迭代器
    对于其他容器,由于其结构特性,上面的功能不一定都有(例如set的迭代器是不能相减求距离的)
*/

//常见问题
/*
    .end()和.rend指向的位置是无意义的值
    对于一个长度为10的数组,for(int i = 0; i < 10; i++) 其中10就是不可以访问到的
    对于一个长度为10的容器,for(auto it = a.begin(); it != a.end(); ++it), .end是不可以访问的
*/

//ps: 如果你跟我一样是菜鸡,那还是老老实实用for循环遍历吧(> _ <)

8.队列

#include <iostream>
#include <queue>
using namespace std;
/*
queue的常见操作,这里的队列就和数据结构一样的队列

empty(): 检查队列是否为空。
size(): 返回队列中的元素数量。
front(): 返回队首元素的引用。
back(): 返回队尾元素的引用。
push(): 在队尾添加一个元素。
pop(): 移除队首元素。
*/
int main(){
    queue<int> q;
    q.push(1);                      //入队
    q.push(2);                      //入队
    q.push(3);                      //入队 

    cout << q.front() << endl;      //返回对首元素 输出 1
    cout << q.back() << endl;       //返回对尾元素 输出 2

    q.pop();                        // 出队

    cout << q.empty() << endl;      // 判空 空返回1 , 非空返回2
    cout << q.size() << endl;       // 输出队列大小

}


9.stack 栈

#include <iostream>
#include <stack>
using namespace std;
/*
push(): 在栈顶添加一个元素。
pop(): 移除栈顶元素。
top(): 返回栈顶元素的引用,但不移除它。
empty(): 检查栈是否为空。
size(): 返回栈中元素的数量

*/
int main(){
    stack<int> s;
    s.push(1);
    s.push(2);
    s.push(3);                      // 入栈

    cout << s.top() << endl;        // 返回栈顶元素 3

    cout << s.empty() << endl;      // 判空。空输出1, 非空返回0

    cout << s.size() << endl;       // 输出 栈的大小

    s.pop();                        // 出栈
}

总结:

建议先学点数据结构的相关知识再进行该容器的学习。

文末附加内容

评论

  1. `1
    Windows Edge
    2 月前
    2026-3-30 21:42:54

    1111

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
下一篇