开篇:修仙之路再启程,探索map
、set
与string
的奥秘
各位道友,上一期我们踏上了STL的修仙之旅,从vector
到sort,从queue到stack,一路走来,大家是不是已经感受到STL的强大与优雅了呢?但修仙之路永无止境,STL的世界也远不止于此!今天,我们将继续踏上新的征程,揭开map
、set
和string
的神秘面纱。
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++编程、修仙世界的奇闻趣事以及更多有趣的技术干货。让我们一起在修仙与编程的世界中探索更多的奥秘!
最后,如果你觉得这篇文章值得一看,不妨点个赞,让更多人看到!你的支持是我创作的最大动力!谢谢!