这篇介绍一下数据结构

1.数组

这个可真的太普遍了,就是一个个数据组合在一起的数据结构,他们之间有一定的顺序,但大多数时候是不相关联的。

格式如下

数据类型 a[所装数据的数量];

这里就要注意了,数组是可以通过数据所在位置来进行索引的(就是通过位置找到他,并且非常快速,这就是数组的优势区间)

但是,用的时候要注意,数组的起始位置为0,就是第一个位置其实叫第00个位置

2.字符串

用它之前也要写他的头文件

#include<string>

3.vector

我觉得他有点像Python里的列表,可以在中间插入数据,也可以在中间删除数据,还可以从末尾加入数据,可以随意索引数据,如果论实现各个功能所需的时间复杂度,vector的速度无疑是快过数组的(但他的第一个位置也叫第00个)

那么他有什么缺点吗?

函数多啊!!!

vector<数据类型>v;#创建方式
v[数据位置];#索引方式
v.push_back(数据);#在末尾放入数据
v.at(数据位置)=    ;#修改该位置数据
v.resize(要装数据的数量);#提前留几个位置,方便索引(vector没法初始化,所以他的初始大小为$0$)
v.insert(位置,数据);#在该位置前插入数据
v.pop_back();#删除末尾数据
v.erase(位置);#删除该位置的数据
······

记不住就没必要记了,反正你用数组也够了

6.栈

tips:记得加头文件

#include<stack>

栈,大概长这样

他可以直接从口放进去,但是他却只能从口出,所以他的数据是先进的后出

stack <数据类型> s;#创建方式
s.push();#放入代码
s.pop();#删除代码
s.top();#索引栈顶
s.empty()#看看他是不是空的
s.size()#纯检查长度来了

相信你也看出来了,他只能索引一个

而且他每次更改也只能一个个改

也就是说……,他删除一个数字,最坏要把所有其他数字全删了,还得把他们都加回来……

我说白了,队列起码还有双端的和会自动排序的,这个栈完全就是

7.队列

用它时也要加一个

#include<queue>

而他长这样

他的代码为

queue <数据类型> q;#创建方式
q.push();#放入代码
q.pop();#删除代码
q.front();#索引队头
q.empty()#看看他是不是空的
q.size()#检查长度来了

他和栈有点相同的一点……

中间的永远无法索引

但是他是两端的,也就是先进去的先出来!

而且他还有他的变种,感兴趣的自行观看

双端队列

需要特殊的头文件

#include<deque>

双端队列就是把栈和队列融合在一起,可以两头进两头出

如图:

这样我们就可以更加便捷的维护了

代码如下

  1. 构造与初始化

deque dq;:默认构造空队列 deque dq(5, 10);:5个值为10的元素 deque dq = {1, 2, 3};:列表初始化

  1. 增删元素(两端高效 O(1))
操作 说明
push_back(val) 尾部插入
push_front(val) ‌头部插入‌ (Vector不支持)
pop_back() 删除尾部元素
pop_front() ‌删除头部元素‌
insert(pos, val) 指定位置插入 (效率较低)
erase(pos) 删除指定位置元素
  1. 访问与查询 front() / back():获取首/尾元素引用 dq[i] / dq.at(i):随机访问(at带越界检查) size() / empty():大小与判空
单调队列

1. 核心定义

单调队列是一种‌特殊的双端队列‌,队列内的元素严格保持单调递增或单调递减的顺序,入队时会自动移除破坏单调性的无效元素,整体操作时间复杂度为O(n)其实还要你自己维护

2. 核心特性

  • 依托双端队列实现,支持两端高效增删
  • 队头元素始终是当前维护区间内的最大值/最小值
  • 所有元素仅入队、出队各一次,无冗余重复遍历

3. 标准操作流程

  1. 队尾维护‌:新元素入队时,从队尾依次弹出所有破坏单调性的元素,保证队列有序
  2. 队头清理‌:从队头弹出超出当前有效区间的过期元素
  3. 获取极值‌:此时队头元素即为当前区间的目标极值

4. 经典应用场景

场景1:滑动窗口最大值

在长度为k的滑动窗口移动过程中,O(n)复杂度输出所有窗口的最大值,是单调队列最典型的入门题。

场景2:前缀和优化子数组问题

比如题「和至少为K的最短子数组」,通过维护单调递增的前缀和队列,快速筛选出满足条件的最短子数组。

5. C++ 核心实现模板

#include <deque>
#include <vector>
using namespace std;

vector<int> maxSlidingWindow(vector<int>& nums, int k) {
    deque<int> dq; // 存储数组下标,方便判断窗口边界
    vector<int> res;
    for(int i = 0; i < nums.size(); i++){
        // 1. 队尾维护:弹出比当前元素小的元素,保持队列单调递减
        while(!dq.empty() && nums[i] >= nums[dq.back()])
            dq.pop_back();
        dq.push_back(i);
        // 2. 队头清理:移除超出窗口范围的过期下标
        if(dq.front() == i - k)
            dq.pop_front();
        // 3. 窗口形成后,记录队头的最大值
        if(i >= k - 1)
            res.push_back(nums[dq.front()]);
    }
    return res;
}
优先队列

1. 核心定义

优先队列说白了就是会排序的队列,他会把数据按照优先级大小来排序,每次出去的都是里面优先级最大的,换句话说,如果是char类型,'A'会比'a'出去的晚(因为char类型的排序是依靠ASCALL码的大小),通常基于二叉堆实现反正你又不知道二叉堆

它不需要额外加头文件,因为他已经在queue里了

2. 核心特性

  • 英文名叫priority_queue,默认是大顶堆
  • 核心操作时间复杂度稳定为O(log n),取队首极值仅需O(1)
  • 支持自定义比较规则,灵活切换大顶堆/小顶堆模式

3. 基础操作速查

操作 说明 时间复杂度
push(val) 插入元素并维护堆结构 O(log n)
pop() 移除优先级最高的队首元素
top() 获取队首极值元素,不删除 O(1)
empty() / size() 判空/获取队列元素总数
priority_queue<> q; 创建方式 这你也想知道?

总而言之,队列大概就是