STL---常见数据结构总结

•前言:

在算法比赛中,如果每一个数据结构都自己手搓的话,将会花费大量的时间来重复造轮子,因此在这里,我总结了一些在算法比赛里 经常使用到的STL的数据结构。

那么我们一起来看看吧。

一.vector

• 初始化:

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;

int main(){
    vector<int> v;//普通初始化,后需要用等于赋值

    vector<int> v(3); // 指定空间,内容为空,等价于 vector<int> v(3,0)

    vector<int> v (3,-1); //指定空间为 3 ,内容为-1

    //二维数组
    vector<vector<int>> m(4,vector<int>(5,2));
}

这里重点说一下这个 二维数组, 指定二维数组初始化值的时候,在构造函数括号里第二个代表列的位置,写下vector<数据类型>(几列,初始化为几).

• 常规操作:

cpp 复制代码
    //交换容器
    v.swap(v1);
    
    //插入
    v.insert(v.begin()+3,5);
}

swap()可以互换容器, insert()和erase()中的参数 是 "迭代器",

v.begin()代表的是数组索引为0的位置**,因此v.begin() + i 就是等于计算数组索引。**

•补充: 二维数组多用于 "网格" ,"矩阵"中,特定情况下用于 实现 "前缀和数组" 前缀和数组-----从零开始的算法-CSDN博客

二.string

string容器支持 "++自动扩容" , "拼接" ,"比较" 登操作++

size() 和 length()成员函数实现的效果,不能说完全相同吧,只能说一模一样,用哪个没区别。

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;

int main(){
    string a = "qwq";

    //拼接
    a =  a + "Hello";

    //用括号访问元素
    cout << a[0] << endl;
    
    //截取字串 substr(起始位置,长度)
    cout << a.substr(0,3) << endl;
    
    system("pause");
    return 0;
}

拼接操作的话,直接使用 "+",在例子中直接把hello,接在了a的后面。

接口 substr(起始位置,长度) ,用于截取字符串中的某一段元素

• 查找函数find() ,比较

cpp 复制代码
    //find()查找
    cout << a.find("Hello") << endl;

    //比较
   cout << (a == "H") << endl;
   cout << (a != "H") << endl;

find()查找到这个元素之后,会返回首先出现位置的下标。

比较: 当符合 运算式时候,会返回 1 ,不符合返回0.

1.字符串和数字的转换

• 字符串转数字

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;

int main(){
    //字符串转int
    int n = stoi("567");
    cout << n << endl;
    
    //字符串转longlong
    long long m = stoll("5678910");
    cout << m << endl;

++**stoi()**字符串转 int , stoll() 字符串转longlong++

• 数字转字符串

cpp 复制代码
    //数字转字符串
    string s = to_string(520);
    cout << s << endl;

    string str = to_string(52.0);
    cout << str << endl;

++to_string()++ 可以把 数字转为字符串。

2. char类型 单字符的判断和转换

<cctype> 提供了函数用于处理 单字符的判断和转换。

• isdigit() 判断是否为 0 - 9 的 数字字符 ,++是返回非零整数 ,不是返回0++

cpp 复制代码
   //isdigit 是否为数字字符 "0" - "9" 
   cout << (isdigit('5') != 0) << endl;
   cout << (isdigit('a') != 0) << endl;

运行结果是 :1 0

• isalpha() 是否为字符 , 是返回非零整数 ,不是返回 0

cpp 复制代码
   // isalpha()
   cout << (isalpha('a') != 0) << endl;

• toupper , tolower 大小写转换

toupper(ch) , tolower(ch) 返回的是 int 类型 ,把ch 转换为 "int" 类型 ,

想得到转换之后的原形怎么办? 很简单! 强制转换为( char )就好了。

ps : 如果把小写字符输入小写转换,会返回本身;大写转换同理

补充一点: isupper()islower() 判断是否是大小写, 是的话返回非0,不是的话返回0

cpp 复制代码
//    cout << (char)islower('a') << endl;
   cout << (char)toupper('a') << endl;
   cout << (char)tolower('a') << endl;

运行结果 : A a

技巧: 字母转数字索引

算法题中非常常见,这个技巧常用于将字母字符映射为从 0 开始的整数索引,便于在数组或哈希表中进行计数、查找等操作。

cpp 复制代码
char c = 'd';
int index = c - 'a';   // index = 3

index 为 3

三.list

list 是 双向链表,支持任意位置插入和删除 ,但是不支持像数组那样随机下标访问元素,因此只能靠迭代器遍历.

前情提要:++advance()是移动迭代器。++,顾名思义就是能把迭代器移动的迭代器。

听起来有点绕,请看下文就会理解了

cpp 复制代码
#include<iostream>
#include<list>
using namespace std;

int main(){
    list<int> lt;
    lt.push_back(1);
    lt.push_back(2);
    lt.push_front(5);
    lt.push_front(4);

    for (auto node : lt){
        cout << node << " ";
    }
    cout << endl;

    auto i = lt.begin();
    advance(i,3);
    lt.insert(i,50);
    for (auto node : lt){
        cout << node << " ";
    }
    cout << endl;
    
    auto it = lt.begin();
    advance(it,2);
    lt.erase(it);
     for (auto node : lt){
        cout << node << " ";
    }

   
    system("pause");
}

advance(迭代器,向后移动几个位置)会移动迭代器 ,配合insert()和 erase(),有助于完成插入和删除操作

在这个例子中:

i 一开始是起始迭代器,通过 advance 移动了 3 个位置,然后插入了 50

四.unordered_map 哈希表

语法:

• 初始化

unordered_map<std:: string , ElementType> 变量名

<>中的第一个数据类型是键, 第二个数量类型代表的是值;通常第一个数据类型用string来表示。

• 添加键值 --- 直接用【】

【】中填键,= 号后面填值

cpp 复制代码
#include<iostream>
#include<unordered_map>
using namespace std;

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

    map["man"] = 3;
    map["cherno"] = 5;
    map["gg"] = 6;

    cout << map["gg"] << endl;
    cout << map["tl"] << endl;
    system("pause");
    return 0;
}

直接通过 形式 :变量名【键】 = value;

访问的时候,如果这个键不存在 ,就比如说在这个例子中

++访问不存在的键 map【tl】 会返回 0(默认)----为什么呢?++

++因此 即使没有给键确定的 value ,它也会默认为 0.++

• 查找函数

map.count("要查找的元素") ---- C++ 11 中 利用 成员函数count 查找,如果存在会返回1 , 不存在返回 0.

• 删除

cpp 复制代码
    cout << map.count("tl") << endl;

    cout << map.size() << endl; // 返回 4 

    map.erase("tl");
    cout << map.size() << endl;  // 返回 3

    system("pause");
    return 0;

第一个返回 4 ,第二个 返回 3

• 遍历

cpp 复制代码
    //遍历:
    for (const auto& node : map){
       cout << node.first << " " << node.second << endl;    
    }

first 就是键 ,second 就是 对应的值。

应用:

1. unordered_map 在算法题中的用途就是 统计频率

cpp 复制代码
    unordered_map<char,int> test;
    string s = "hello";
    for (auto &node : s){
        test[node]++;
    }
    
    //遍历
    for (auto & node: test){
        cout << node.first << " " << node.second << endl;
    }

通过遍历循环,然后存入哈希表中。

五.map --- 有序表--之后更新

六.unordered_set 哈希集合

哈希集合本质上就是底层在哈希表的基础上拓展而来的,

++相较于哈希表,哈希集合是不会储存重复元素的++

哈希集合只储存 key,不储存对应的value ----不储存相同元素的底层原因。

例子: unordered_set<int> a; // 之前已经插入过 10

当 a.insert(10) : 最后哈希表中不会有两个10,循环后会发现只有一个10.

• 初始化:

unorder_set <数据类型> 变量名

•插入 insert()

cpp 复制代码
#include<iostream>
#include<unordered_set>
using namespace std;


int main(){
    unordered_set<int> a;
     
    a.insert(1);
    a.insert(5);
    a.insert(10);
    for (auto &node : a){
        cout << node << " ";
    }
    cout << endl;

    //重复插入无效
    a.insert(10);
        for (auto &node : a){
        cout << node << " ";
    }
    cout << endl;

    system("pause");
    return 0;
}

通过两次遍历会发现,a中只储存了一个 10

遍历同理---哈希表底层是数组。

七. set 有序集合---后续更新

八.队列 / 栈

详细请看这一篇:队列/栈的基本原理与实现----从零开始的数据结构学习-CSDN博客

九. priority_queue---优先队列---后续更新

十.pair ---结构化绑定

pair的头文件有点不同 ,不是以本身命名的-----#include ++<utility>++

pair 实际上就是类似结构体的逻辑,能够把不同的数据类型整合成一个类型

• 初始化

pair <第一个数据类型,第二数据类型> 变量名

成员变量中: first---第一个数据, second --- 第二个数据(这里和哈希表类似

cpp 复制代码
#include<iostream>
#include<utility>
using namespace std;

int main(){
    pair<string,int> p1("man",3);
    pair<string,int> p2 = {"ok",5};

• 比较

直接用比较运算符就行

第一个对象如果相同,就会比较第二对象 ,

正确就输出1,错误就输出0

cpp 复制代码
    pair<string,int> p1("man",3);
    pair<string,int> p2 = {"ok",5};
    
    cout << p1.first << endl;
    cout << p1.second << endl;

    cout << (p1 > p2) << endl;

会输出0,第一个类型中 ok 的 "o" 大于 man 中的 "m" (好吧我承认这个变量有点奇怪)。

结语:

如果喜欢的话,不妨点一个免费的赞和收藏,你们的支持就是我不断前进的动力之一。

我后续也会不断更新优秀的文章,欢迎各位股东关注!!!

当然,这篇文章还有没有更新完的部分,我后续会不断改进的, respect 。

相关推荐
斌味代码2 小时前
Next.js 14 App Router 完全指南:服务端组件、流式渲染与中间件实战
开发语言·javascript·中间件
H Journey2 小时前
C++ 11 新特性 基于范围的for循环
c++·c++11·for循环
无限进步_2 小时前
【C++】反转字符串的进阶技巧:每隔k个字符反转k个
java·开发语言·c++·git·算法·github·visual studio
智算菩萨2 小时前
【Python图像处理】6 图像色彩空间转换与通道操作
开发语言·图像处理·python
小琪爱学习2 小时前
项目学习代码
学习
kaico20182 小时前
python基础
开发语言·python
551只玄猫2 小时前
【数学建模 matlab 实验报告11】拟合
开发语言·数学建模·matlab·数据分析·课程设计·实验报告·拟合
Ulyanov2 小时前
Python与YAML的优雅交响:从配置管理到数据艺术的完美实践 (一)
开发语言·前端·python·数据可视化
菜菜小狗的学习笔记2 小时前
八股(一)Java基础
java·开发语言