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 。

相关推荐
cpp_25011 天前
P1024 [NOIP 2001 提高组] 一元三次方程求解
数据结构·c++·算法·题解·二分答案·洛谷·csp
小羽网安1 天前
从零开始学习 sql 注入,常见的 sql 注入解析
数据库·sql·学习
Gofarlic_oms11 天前
利用API实现ANSYS许可证管理自动化集成
运维·服务器·开发语言·matlab·自动化·负载均衡
AI+程序员在路上1 天前
VS Code 完全使用指南:下载、安装、核心功能与 内置AI 编程助手实战
开发语言·人工智能·windows·开源
invicinble1 天前
这里对java的知识体系做一个全域的介绍
java·开发语言·python
catchadmin1 天前
使用 PHP TrueAsync 改造 Laravel 协程异步化的可行路径
开发语言·php·laravel
wbs_scy1 天前
【Linux 线程进阶】进程 vs 线程资源划分 + 线程控制全详解
java·开发语言
stm32 菜鸟1 天前
nucleo-f411re学习记录-12,Wifi模块ESP8684
学习
AI人工智能+电脑小能手1 天前
【大白话说Java面试题】【Java基础篇】第15题:JDK1.7中HashMap扩容为什么会发生死循环?如何解决
java·开发语言·数据结构·后端·面试·哈希算法
郑州光合科技余经理1 天前
同城O2O海外版二次开发实战:从支付网关到配送算法
开发语言·前端·后端·算法·架构·uni-app·php