算法篇-炼气期-STL库函数与数据结构(下篇)

开篇:修仙之路再启程,探索mapsetstring的奥秘

  各位道友,上一期我们踏上了STL的修仙之旅,从vectorsort,从queuestack,一路走来,大家是不是已经感受到STL的强大与优雅了呢?但修仙之路永无止境,STL的世界也远不止于此!今天,我们将继续踏上新的征程,揭开mapsetstring的神秘面纱。

map映射

map:藏宝图的秘密
  在修仙界,寻宝是一项至关重要的任务。想象一下,如果你是一位寻宝者,在茫茫大山中寻找珍稀的灵石,却没有一张精准的藏宝图,那该是多么痛苦的事情!而map就是这张藏宝图!它能让你以闪电般的速度找到所需的“宝藏”,堪称修仙界的“索引大师”。无论是存储数据还是快速查找,map都能让你事半功倍。

#include <map>--引入头文件

提供对数时间的有序键值对结构。底层原理是红黑树。(红黑树是元婴期内容-敬请期待哦)

构造

map<键类型, 值类型, 比较器> mp

  • 键类型:要储存键的数据类型
  • 值类型:要储存值的数据类型
  • 比较器:键比较大小使用的比较器,默认为 less<类型>,可自定义
map<int, int> mp1;               // int->int 的映射(键从小到大)
map<int, int, greater<int>> st2; // int->int 的映射(键从大到小)

遍历map的三种“魔法”

在修仙界,map就像一本藏宝图,里面记录着各种“宝藏”(键值对)。要找到这些宝藏,我们需要学会如何遍历map。以下是三种“寻宝”方法:

使用迭代器进行遍历

for (map<int, int>::iterator it = mp.begin();  it != mp.end();  ++it) {
    cout << "灵石编号:" << it->first << " 数量:" << it->second << endl;
}

解读: 这是传统的寻宝方式,逐个查看藏宝图上的每一个标记点。虽然有点老套,但绝对可靠。

基于范围的循环(C++ 11)

for (auto &pr : mp) {
    cout << "灵石编号:" << pr.first  << " 数量:" << pr.second  << endl;
}

解读: 这是更现代化的寻宝方式,直接遍历藏宝图上的每一个宝藏信息,简洁高效。

结构化绑定 + 基于范围的循环(C++17)

for (auto &[key, val] : mp) {
    cout << "灵石编号:" << key << " 数量:" << val << endl;
}

解读: 这是最先进的寻宝方式,直接解构出灵石编号和数量,方便快捷。

藏宝图的操作技巧-增 / 改 / 查元素

mp[1] = 2; // 在藏宝图中标记灵石1的数量为2

查找元素(返回迭代器)

auto it = mp.find(1);  // 在藏宝图上查找灵石1的位置

删除元素

mp.erase(2);  // 从藏宝图上移除灵石2的信息

判断元素是否存在

if (mp.count(3))  { // 检查藏宝图上是否有灵石3的记录
    // 存在处理逻辑
}

查看大小 / 清空 / 判空

cout << "藏宝图上有" << mp.size()  << "个灵石记录" << endl; // 查看藏宝图上的记录总数
mp.clear();  // 清空整个藏宝图
if (mp.empty())  { // 检查藏宝图是否为空
    // 处理逻辑
}

寻宝效率:时间复杂度

map 的增删改查操作的时间复杂度均为 O(log n)。这意味着无论你的藏宝图有多大,寻宝的速度都不会变得太慢。

适用情形(例子)

输入若干字符串,统计每种字符串的出现次数

map<string, int> word_count;
string input;
while (cin >> input) {
    word_count[input]++; // 自动记录每个字符串的出现次数
}

注意事项

中括号访问时默认值

map<char, int> mp;
cout << "初始状态:'a'是否存在?" << mp.count('a')  << endl; // 输出0,表示不存在
mp['a']; // 这里看似没做什么,但其实已经在藏宝图上创建了'a'的记录,默认数量为0
cout << "操作后:'a'是否存在?" << mp.count('a')  << endl; // 输出1,表示存在
cout << "'a'的数量:" << mp['a'] << endl; // 输出0

使用中括号访问时,如果对应的键不存在,系统会自动创建这个键,并设置默认值。这可能会导致意外的记录创建。

集合set

修仙法宝录:Set的奥秘

  在修仙界,法宝是修士们不可或缺的伙伴。想象一下,如果你是一位修士,在修炼途中需要收集各种灵石、丹药或符咒,却没有一件能够帮你管理这些珍贵物品的法宝,那该是多么麻烦的事情!而set就是这件法宝!它能让你轻松管理独一无二的“珍宝”,堪称修仙界的“收纳大师”。无论是存储数据还是快速查找,set都能让你得心应手。


法宝初探:Set的基本用法

set是一种特殊的容器,用于存储唯一且有序的元素。它就像一件能够自动整理和筛选的法宝,确保你收集的每一件珍宝都是独一无二的。

#include <set>

构造

set<类型, 比较器> st

  • 类型:要储存的数据类型
  • 比较器:比较大小使用的比较器,默认为 less<类型>,可自定义
  • set<int> st1;               // 储存int的集合(从小到大)
    set<int, greater<int>> st2; // 储存int的集合(从大到小)

定义与初始化

#include <set>
using namespace std;
 
int main() {
    // 初始化一个空的set 
    set<int> s;
 
    // 初始化一个包含特定元素的set 
    set<int> s2 = {1, 3, 2, 3}; // 元素自动去重,并按升序排列 
    // s2中的元素为:1, 2, 3 
 
    return 0;
}

解读: 这是set的基本形态。当你向set中添加元素时,它会自动去除重复项,并将元素按顺序排列。这就像是一件能够自动筛选和整理的法宝。


寻宝之旅:如何遍历Set

使用迭代器进行遍历

for (set<int>::iterator it = s.begin();  it != s.end();  ++it) {
    cout << "灵石编号:" << *it << endl;
}

基于范围的循环(C++ 11)

for (auto &val : s) {
    cout << "灵石编号:" << val << endl;
}

法宝的操作技巧

查找元素(返回迭代器)

auto it = s.find(3);  // 在set中查找编号为3的灵石 

插入元素

s.insert(5);  // 向set中插入一个新元素 

删除元素

s.erase(2);  // 从set中移除编号为2的灵石 

判断元素是否存在

if (s.count(3))  { // 检查set中是否有编号为3的灵石 
    // 存在处理逻辑 
}

查看大小 / 清空 / 判空

cout << "法宝中有" << s.size()  << "个灵石" << endl; // 查看set中的元素总数 
s.clear();  // 清空整个set 
if (s.empty())  { // 检查set是否为空 
    // 处理逻辑 
}

法宝效率:时间复杂度

set 的增删改查

操作的时间复杂度均为 O(log n)。这意味着无论你的set有多大,操作速度都不会变得太慢。

注意事项

自动去重
set<int> s;
s.insert(1);  // 插入1 
s.insert(1);  // 再次插入1,set会自动忽略 
cout << "s中是否有1?" << s.count(1)  << endl; // 输出1 
cout << "s中有多少个1?" << s.count(1)  << endl; // 输出1(因为set只存储一个)
无序性
// 错误示例:
set<int> s = {3, 1, 2};
for (int i = 0; i < s.size();  ++i) {
    cout << s[i] << endl; // 这是错误的!set不能通过下标访问元素 
}

字符串String

修仙符箓录:String的奥秘

  在修仙界,符箓是修士们必不可少的工具。想象一下,如果你是一位修士,在修炼途中需要记录各种口诀、咒文或秘籍,却没有一件能够帮你高效管理文字的法宝,那该是多么麻烦的事情!而string就是这件法宝!它能让你轻松管理文字信息,堪称修仙界的“符箓大师”。无论是存储文字还是快速操作,string都能让你得心应手。


构造与初始化

#include <string>
using namespace std;
 
int main() {
    // 初始化一个空的string 
    string s;
 
    // 初始化一个包含特定字符的string 
    string s2 = "awa!"; // 直接赋值字符串 
 
    // 通过构造函数初始化 
    string s3(10, '6'); // 创建一个长度为10,内容为'6'的字符串 
    // s3的内容为:"6666666666"
 
    return 0;
}

符箓的骚操作(必会)

修改与查询指定下标字符

s[1] = 'a'; // 修改字符串中索引为1的字符为'a'

尾接字符串

s += "awa"; // 在原字符串末尾追加"awa"

取子串

string sub = s.substr(2,  10); // 从索引2开始取长度为10的子串 

查找字符串

int pos = s.find("awa");  // 查找"awa"在字符串中的位置 

数值与字符串互转(C++11)

// 数值转字符串 
int num = 123;
string s_num = to_string(num); // s_num的内容为"123"
 
// 字符串转数值 
string s_int = "456";
int int_val = stoi(s_int); // int_val的值为456 

大小写字母转换

1. toupper 和 tolower

这两个函数是单字符转换的“基础法术”,适用于逐个字符的转换。

#include <cctype> // 包含头文件 
#include <string>
using namespace std;
 
int main() {
    char c = 'a';
    cout << "原始字符:" << c << endl;
    
    // 将小写字母转换为大写字母 
    c = toupper(c);
    cout << "转换后:" << c << endl; // 输出:A 
    
    c = 'A';
    cout << "原始字符:" << c << endl;
    
    // 将大写字母转换为小写字母 
    c = tolower(c);
    cout << "转换后:" << c << endl; // 输出:a 
    
    return 0;
}

2. transform:批量转换字符串

如果你需要批量转换字符串中的所有字符,transform 函数就是你的“终极法术”。

#include <algorithm> // 包含头文件 
#include <string>
using namespace std;
 
int main() {
    string s = "Hello, World!";
    cout << "原始字符串:" << s << endl;
    
    // 将所有字符转换为大写字母 
    transform(s.begin(),  s.end(),  s.begin(),  ::toupper);
    cout << "转换后:" << s << endl; // 输出:HELLO, WORLD!
    
    // 将所有字符转换为小写字母 
    transform(s.begin(),  s.end(),  s.begin(),  ::tolower);
    cout << "转换后:" << s << endl; // 输出:hello, world!
    
    return 0;
}

解读:

  • transform 是一个强大的算法函数,可以批量处理字符串中的所有字符。
  • 第一个参数是字符串的起始迭代器(s.begin() )。
  • 第二个参数是字符串的结束迭代器(s.end() )。
  • 第三个参数是目标迭代器(这里指向字符串的起始位置,表示在原字符串上进行修改)。
  • 第四个参数是转换函数(::toupper 或 ::tolower)。

符箓注意事项

.substr()方法的参数

// 错误示例:
string s = "abcdef";
string sub = s.substr(2,  3); // 子串起点为2,长度为3,结果为"def"
// 注意:第二个参数是子串长度,而不是子串终点!
 
// 正确示例:
sub = s.substr(2,  3); // 正确获取子串"def"

关注与点赞

  感谢你耐心阅读这篇博客!如果你觉得这篇文章对你有所帮助,或者你对C++编程还有其他疑问,欢迎在评论区留言交流。你的反馈是我不断进步的动力!

  如果你喜欢我的内容,也欢迎关注我的博客或社交媒体账号。我会持续分享更多关于C++编程、修仙世界的奇闻趣事以及更多有趣的技术干货。让我们一起在修仙与编程的世界中探索更多的奥秘!

  最后,如果你觉得这篇文章值得一看,不妨点个赞,让更多人看到!你的支持是我创作的最大动力!谢谢! 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Starry-Walker

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值