(双手合十,周身泛起淡淡的代码灵光)诸位道友且慢划走!今天我们不聊金丹元婴那些唬人的大神通,来点实在的——本座夜观天相,发现菜鸟修仙者十有八九不是被红黑二叉树压断灵根,就是在动态规划的心魔劫里走火入魔。但你们可知?只要炼化这枚名为STL的上古储物戒,就能让键盘自动结出算法法印,从此在力扣秘境横着走!(突然压低声音)上个月本座亲眼见证,某个连冒泡排序都要掐诀半柱香的萌新,靠着STL三件套竟在Codeforces战场连破十八铜人阵...(突然闪现到镜头前,手中vector绽放金光)欲知后事如何?且看今日《从炼气到筑基:STLの千层套路》!
本文适合人群:算法比赛萌新,学习C++的兄弟们
STL 作为一个封装良好,性能合格的 C++ 标准库,在算法竞赛中运用极其常见。灵活且正确使用 STL 可以节省非常多解题时间,这一点不仅是由于可以直接调用,还是因为它封装良好,可以让代码的可读性变高,解题思路更清晰,调试过程 往往 更顺利。
诸位道友,当你面对十来个乱序的修士要按修为排队时,总不会真的左手拎着for循环炼丹瓶,右手捏着if语句指挥旗,亲自当教导主任吧?看好了!这sort函数可是修真界包邮的自动整队神器—
基础操作:
只需掏出 sort(咸鱼堆.begin(), 咸鱼堆.end(), 比较函数);
,再给这个“比较函数”注入灵魂:(默认是从小到大,这个咸鱼堆可以是结构体或者数组等)
实际上在一般的算法题中大部分都涉及到结构体的复杂排序,而不是简单的数组排序
下面是如何实现按结构体中某个元素排序的代码
struct 咸鱼修士 {
int 修为境界; // 从996到007不等
string 道号; // 比如"码奴真人"
double 摸鱼指数; // 越高越容易在coding时刷淘宝
};
//排序函数写在结构体外面(重载的写法-写在结构体内部)
bool 卷王选拔赛(const 咸鱼修士& 甲, const 咸鱼修士& 乙) {
// 境界高的排前面,境界相同则摸鱼少的优先
if(甲.修为境界 != 乙.修为境界)
return 甲.修为境界 > 乙.修为境界;
else
return 甲.摸鱼指数 < 乙.摸鱼指数;
}
懒人渡劫:
要是连比较函数都懒得写?直接给结构体穿上运算符重载的仙履:
struct 咸鱼修士 {
...
bool operator<(const 咸鱼修士& 他修) const {
// 自动按修为升序,摸鱼指数降序排列
return tie(修为境界, -摸鱼指数) < tie(他修.修为境界, -他修.摸鱼指数);
}
};
// 使用时只需 sort(咸鱼堆.begin(), 咸鱼堆.end());
注意点:结构体排序自定义(注意传递参数的时候用上引用--提高排序的速度)
#include
--引入头文件 构造
vector<类型> arr(长度, [初值])
连续的顺序的储存结构(和数组一样的类别),但是有长度可变的特性。
vector arr; // 构造int数组
vector arr(100); // 构造初始长100的int数组
vector arr(100, 1); // 构造初始长100的int数组,初值为1
vector> mat(100, vector ()); // 构造初始100行,不指定列数的二维数组
vector> mat(100, vector (666, -1)) // 构造初始100行,初始666列的二维数组,初值为-1
【尾接 & 尾删】
当你的vector
像贪吃蛇修炼成精:
vector 乾坤袋; // 修真界祖传储物袋
乾坤袋.push_back(114514); // 往屁股塞灵石,胖+1(均摊下来约等于白嫖)
乾坤袋.push_back(1919810); //
乾坤袋.pop_back(); // 拉肚子!瘦-1(掉出来的是不是米田共要看元素类型)
【中括号耍流氓】
比御剑飞行还快的随机访问:
vector 仙丹名录 = {"筑基丹", "结金丹", "渡劫丸"};
cout << 仙丹名录[0]; // 输出"筑基丹" —— 注意修真界数组从零开始计数!
仙丹名录[2] = "后悔药"; // 把第三个丹药偷梁换柱(道友:这很修真)
【尺寸把脉术】
if(乾坤袋.size() > 10086)
cout << "储物袋要撑爆啦!"; // size()如同照妖镜现原形
while(!仙丹名录.empty()) { // empty()检查是否被吃干抹净
cout << "嗑药中..." << endl;
仙丹名录.pop_back(); // 嗑药姿势请勿模仿
}
【乾坤大挪移】
vector 灵石堆(3, 3.14); // 初始化3块圆周率灵石
灵石堆.resize(5, 6.66); // 强行扩容到5块,新增的塞入恶魔数字
// 现在灵石堆:[3.14,3.14,3.14,6.66,6.66]
灵石堆.resize(2); // 渡劫失败被打回原形
// 只剩前两块:[3.14,3.14]
【清空警告】
vector 黑历史 = {'社','死','场','景'};
黑历史.clear(); // 一键消除记忆(注意:并不会释放内存!)
cout << 黑历史.size(); // 输出0,但修真界都知道你只是假装遗忘
普通数组:像凡铁打造的储物袋,容量固定还容易划破手
vector:自动扩容的须弥芥子空间,自带防爆符(除非遇到卡时间的变态题)
#include
通过二次封装双端队列 (deque) 容器,实现先进先出的队列数据结构。
作用 | 用法 | 示例 |
---|---|---|
构造 | queue<类型> que |
queue |
进队 | .push(元素) |
que.push(1); |
出队 | .pop() |
que.pop(); |
取队首 | .front() |
int a = que.front(); |
取队尾 | .back() |
int a = que.back(); |
不可访问内部元素!--即不能用下标queue[i]直接访问元素
#include
提供常数时间的最大元素或最小元素查找,对数时间的插入与提取,底层原理是二叉堆。(二叉堆为结丹期内容-敬请期待)
priority_queue<类型, 容器, 比较器> pque
- 类型:要储存的数据类型
- 容器:储存数据的底层容器,默认为
vector<类型>
,竞赛中保持默认即可- 比较器:比较大小使用的比较器,默认为
less<类型>
,可自定义
【修真界天梯排行榜——priority_queueの奥义】
核心设定:
这货就是个不讲武德的比武场——永远只能看见榜首大佬,其他修士全被压在五行山下!--最值永远自动排在堆顶(大根堆,小根堆)
1. 进堆渡劫(.push())
priority_queue 天梯榜; // 默认是大佬在上(最大堆)
天梯榜.push(996); // 996福报修士入场
天梯榜.push(007); // 间谍修士试图上位
天梯榜.push(114514); // 神秘数字君直接霸榜
// 当前榜首:114514(自动把最大的顶到最前面)
2. 榜首飞升(.pop())
天梯榜.pop(); // 榜首渡劫成功,原地飞升
// 新晋榜首:996(此时007还在山下骂街)
警告: 空队列使用pop()会引发天劫——段错误雷劈!
3. 偷窥榜首(.top())
if(!天梯榜.empty())
cout << "当前卷王:" << 天梯榜.top(); // 输出996
else
cout << "天梯空荡荡,道友在摆烂";
1. 榜单潜规则
只能看榜首(其他道友在渡劫期不可观测):-并且不能用中括号[1]访问-->.top()
全员禁止改命(修真界禁止开挂):
// 作死操作:
天梯榜.top() = 251; // 试图篡改榜首修为
// 编译器怒斥:error: top()返回的是const引用!
int 临时修为 = 天梯榜.top();
天梯榜.pop();
天梯榜.push(临时修为 + 10086); // 飞升后重修归来
想让弱鸡排前面? 给priority_queue灌反向毒奶:
// 小顶堆の秘法(修为低的反而排前面)
priority_queue, greater> 咸鱼榜;
咸鱼榜.push(999);
咸鱼榜.push(1);
cout << 咸鱼榜.top(); // 输出1 —— 真正的摆烂之王!
结构体比武大会(接上回咸鱼修士):
struct 咸鱼修士 { /* 同前文定义 */ };
// 自定义比较器:按摸鱼指数从高到低排列
struct 摸鱼之王比较器 {
bool operator()(咸鱼修士 甲, 咸鱼修士 乙) {
return 甲.摸鱼指数 < 乙.摸鱼指数; // 摸鱼越多越牛逼
}
};
priority_queue<咸鱼修士, vector<咸鱼修士>, 摸鱼之王比较器> 摸鱼榜;
终极奥义:
当你在LeetCode秘境遇到以下场景,请祭出priority_queue本命法宝:
要实时找最大/最小(比如合并K个有序数组)
数据流中持续维护Top K(比如监控修真界打赏榜)
贪心算法需要(比如宗门派发灵石时优先满足哭得最大声的)
由于堆在比赛中十分常见,而其他的STL是作为基础,很少有单独考察的。所以作者在这放一道关于堆排序的问题作为练手
Kth Largest Element in an Array - LeetCode
#include
通过二次封装双端队列 (deque) 容器,实现先进后出的栈数据结构。
构造
stack<类型> stk
【修真界后悔药专卖店——stackの奥义】
核心设定:
这玩意儿就是个只能"后进先出"的炼丹炉——最后塞进去的丹药,总是最先炸炉!
1. 嗑药入栈(.push())
stack 后悔药柜; // 专门存放"早知道就该..."
后悔药柜.push("不该用冒泡排序");
后悔药柜.push("不该在周五晚上提交代码");
后悔药柜.push("不该和产品经理吵架");
// 当前炉顶丹药:"不该和产品经理吵架"
2. 炸炉反悔(.pop())
后悔药柜.pop(); // 吞下最新一颗后悔药
// 现在炉顶变成:"不该在周五晚上提交代码"
3. 偷看炉顶(.top())
if(!后悔药柜.empty())
cout << "最后悔的事:" << 后悔药柜.top();
else
cout << "无事可悔,道友已成圣";
试图偷窥丹炉内部?(走火入魔预警)
// 作死循环法(实际会打印乱码)
for(int i=0; i<后悔药柜.size(); i++){
cout << 后悔药柜[i] << endl; // 报错!stack没有[]操作符
}
// 作死迭代法(引发编译器天劫)
for(auto& 悔意 : 后悔药柜){
cout << 悔意; // 报错!stack不支持迭代器
}
需要"吃后悔药"的场景(函数调用栈、撤销操作)
对称结构检测(括号匹配、回文校验)
深度优先搜索(DFS时用来记录路径)
各位道友,经过一番修仙之旅,我们终于走完了STL的基础修炼之路。
map
、set
与string
第一站:map
——藏宝图的秘密
想象你是一位寻宝者,map
就是你的藏宝图!它能让你以闪电般的速度找到所需的“宝藏”,堪称修仙界的“索引大师”。下篇我们将深入探讨它的奥秘!
第二站:set
——炼丹炉的玄妙
set
就像一台神奇的炼丹炉,不仅能去除重复的“杂质”,还能自动排序,炼出纯净的“丹药”。无论是普通丹药还是珍贵灵丹,它都能助你一臂之力!
第三站:string
——修仙者的法器
string
是程序员手中的法器!它可以帮你轻松处理文字、字符,甚至施展魔法般的操作(比如拼接、查找、替换)。无论是撰写经文还是炼制符咒,它都能让你得心应手!
如果你觉得这篇总结还不错,请记得点个赞、留个言!如果你还没有关注我的博客,也欢迎关注一下,获取更多修仙干货!下篇我们将继续为你揭开STL的神秘面纱,敬请期待!