文章目录
- 💯前言
- 💯题目描述
- 💯题目描述
- 输入格式
- 输出格式
- 示例输入与输出
- 输入:
- 输出:
- 💯我的做法
- 操作1:在文档末尾插入字符串
- 操作2:截取字符串
- 操作3:在指定位置插入字符串
- 操作4:查找子串位置
- 完整代码:
- 💯老师的做法
- 主要差异
- 代码:
- 💯对比分析
- 相同点:
- 差异点:
- 💯扩展与优化
- 💯小结
💯前言
- 在本次编程练习中,我们的目标是设计并实现一款文字处理软件。题目要求我们通过一系列字符串操作,模拟文字处理过程。这些操作包括字符串的拼接、截取、插入和查找,操作的结果需及时输出。这类问题不仅考察了我们对 C++ 中字符串操作的掌握,也考察了如何根据不同需求选择合适的数据结构和算法。通过这篇文章,我们将详细分析题目中的要求、我的实现方法、老师的实现方式,并进行对比,最终扩展和总结整个思路。
C++ 参考手册
💯题目描述
以下是题目原文,要求根据输入的操作来处理文档内容,并输出结果:
💯题目描述
P5734 【深基6.例6】文字处理软件
你需要开发一款文字处理软件。最开始时输入一个字符串作为初始文档。可以认为文档开头是第 0 个字符。需要支持以下操作:
1 str
:后接插入,在文档后面插入字符串str
,并输出文档的字符串;2 a b
:截取文档部分,只保留文档中从第a
个字符起b
个字符,并输出文档的字符串;3 a str
:插入片段,在文档中第a
个字符前面插入字符串str
,并输出文档的字符串;4 str
:查找子串,查找字符串str
在文档中最先的位置并输出;如果找不到输出-1
。
为了简化问题,规定初始的文档和每次操作中的 str
都不含有空格或换行。最多会有 q
次操作。
输入格式
第一行输入一个正整数 q
,表示操作次数。
第二行输入一个字符串 str
,表示最开始的字符串。
第三行开始,往下 q
行,每行表示一个操作,操作如题目描述所示。
输出格式
一共输出 q
行。
对于每个操作 1,2,3
,根据操作的要求输出一个字符串。
对于操作 4
,根据操作的要求输出一个整数。
示例输入与输出
输入:
4
ILove
1 Luogu
2 5 5
3 3 guGugu
4 gu
输出:
ILoveLuogu
Luogu
LuoguGugugu
3
💯我的做法
在我自己的实现中,我依赖了 C++ 中标准库提供的 string
类型,它使得字符串操作变得非常简单。主要操作如下:
操作1:在文档末尾插入字符串
我选择了使用 +=
运算符来将字符串拼接到文档末尾,代码如下:
s += str;
这样实现可以将新字符串 str
添加到当前文档 s
的末尾,符合题目的要求。
操作2:截取字符串
对于操作2,我使用了 substr(a, b)
函数来截取文档中的一部分。substr
函数接受两个参数,a
为起始位置,b
为截取长度。根据题目要求,我们需要将起始位置从 1-based 转换为 0-based,因此在调用 substr
时,将 a - 1
作为起始位置:
s = s.substr(a - 1, b);
操作3:在指定位置插入字符串
为了在指定位置插入字符串,我使用了 insert(a, str)
方法。这个方法会将字符串 str
插入到当前字符串 s
的第 a
个位置:
s.insert(a - 1, str);
注意这里的 a - 1
是因为题目给定的是 1-based 索引,而 C++ 的字符串操作是基于 0-based 索引的。
操作4:查找子串位置
对于操作4,我使用了 find(str)
函数来查找子串 str
在文档中最早出现的位置。如果没有找到该子串,find
函数会返回 string::npos
,表示未找到:
size_t pos = s.find(str);
if (pos == string::npos)cout << -1 << endl;
elsecout << pos << endl;
完整代码:
#include <iostream>
#include <string>
using namespace std;int main()
{int n;cin >> n;string s;cin >> s;while(n--){int m;cin >> m;switch(m){case 1:{string s2;cin >> s2;s += s2;cout << s << endl;break;}case 2:{int a, b;cin >> a >> b;s = s.substr(a, b);cout << s << endl;break;}case 3:{int a;string s2;cin >> a >> s2;s.insert(a, s2);cout << s << endl;break;}case 4:{string s2;cin >> s2;size_t idex = s.find(s2);if(idex == string::npos)cout << -1 << endl;elsecout << idex << endl;break;}}}return 0;
}
💯老师的做法
老师的做法和我类似,核心思路没有变化,采用了 C++ 标准库的 string
类型及其内置的操作函数。具体代码如下:
主要差异
-
变量初始化:
- 老师在代码开始时就预定义了变量
a
,b
, 和str
,而我的做法是在每个操作中根据需要动态定义这些变量。 - 老师的代码将变量定义放在了
while
循环外部,而我的做法将这些变量放在了每个switch
语句内,确保了在每个操作中只定义所需变量。
- 老师在代码开始时就预定义了变量
-
使用
switch
语句:- 老师使用了
switch
语句来处理不同的操作,明确区分了不同的操作类型。这种方式在处理多个互斥操作时非常清晰,且便于扩展。
- 老师使用了
-
查找操作:
- 在查找子串的部分,老师也使用了
find
函数,并且处理了找不到子串时返回-1
的逻辑,和我的做法相同。
- 在查找子串的部分,老师也使用了
代码:
#include <iostream>
#include <string>
using namespace std;int main()
{int q = 0;cin >> q;string s;cin >> s;int a, b;string str;while (q--){int m = 0;cin >> m;switch (m){case 1:cin >> str;s += str;cout << s << endl;break;case 2:cin >> a >> b;s = s.substr(a, b);cout << s << endl;break;case 3:cin >> a >> str;s.insert(a, str);cout << s << endl;break;case 4:cin >> str;size_t pos = s.find(str);if (pos == string::npos)cout << -1 << endl;elsecout << pos << endl;break;}}return 0;
}
💯对比分析
相同点:
-
操作逻辑:
- 两种实现都处理了 4 种操作,分别是插入、截取、插入指定位置、查找子串。
- 都使用了
string
类型的操作函数,如+=
,substr
,insert
, 和find
来执行字符串操作。
-
输入输出:
- 输入格式一致,读取
q
次操作并执行,每次执行后输出对应结果。
- 输入格式一致,读取
差异点:
-
变量定义:
- 我的做法在每个操作前定义变量,使得每次操作只在需要的时候初始化变量。老师则将变量统一提前定义,这在一些情况下可能更清晰,尤其是在处理较为复杂的逻辑时。
-
代码结构:
- 我选择了将每个操作的代码放在
switch
语句的各个分支中,老师则将更多的内容放在switch
外部,尤其是变量的定义和初始化。
- 我选择了将每个操作的代码放在
💯扩展与优化
-
优化字符串拼接:
- 在频繁拼接字符串的情况下,
+=
运算符可能会有性能问题,尤其是当字符串较长时。为了提高效率,可以使用stringstream
或vector<char>
来减少内存重分配带来的开销。
- 在频繁拼接字符串的情况下,
-
边界检查:
- 对于操作 2 和操作 3,程序没有进行充分的边界检查。如果
a
和b
超出了文档长度范围,应当做适当的处理。比如,在执行substr(a, b)
时,可以检查a + b
是否超过字符串的最大长度。
- 对于操作 2 和操作 3,程序没有进行充分的边界检查。如果
-
容错性:
- 对于查找子串操作,可以加入更多的异常处理机制,例如对输入的子串进行合法性校验,防止空串或无效字符导致异常。
💯小结
本次文字处理软件题目考察了 C++ 中字符串的基本操作,特别是如何通过不同的方式处理字符串的拼接、截取、插入和查找。通过两种实现方法的对比,我们不仅看到了不同的实现方式,也发现了每种方法的优缺点。在实际编码中,我们可以根据具体情况选择合适的方式来实现。通过这些操作,我们能够更深入地理解 C++ 字符串的操作特性,并提升自己的编程能力。