RLE压缩适用于含大量连续重复字符的字符串,如“aaabbbcccc”、日志空格、BMP纯色行;对随机字符串反而膨胀,不适用于JSON或代码。

什么时候该用RLE压缩字符串
RLE(Run-Length Encoding)只对含大量连续重复字符的字符串有效,比如 "aaabbbcccc"、日志中的长串空格、BMP图像的纯色行。对随机字符串(如 "hello world")压缩后反而更长——它不加密、不通用,只是最朴素的“数数+拼接”。别拿它去压JSON或代码。
典型适用场景:
- 生成式文本中重复符号(如 "----====----)
- 嵌入式设备里缓存状态字符串(如 "000000011111")
- 预处理阶段做轻量级去冗余,后续再套其他算法
手写RLE压缩函数要注意的边界
C++标准库没提供现成RLE,得自己写。核心逻辑是遍历字符串,统计每段相同字符的长度。但容易漏掉三类边界:
- 空字符串:
""→ 应返回空字符串,别直接访问str[0] - 单字符:
"a"→ 输出应为"1a",不是"a"(RLE必须带计数) - 末尾断点:循环结束时最后一段未处理,必须在循环外补一次拼接
示例实现(支持ASCII,不处理Unicode):
std::string rle_compress(const std::string& s) {
if (s.empty()) return "";
std::string out;
char curr = s[0];
int count = 1;
for (size_t i = 1; i < s.length(); ++i) {
if (s[i] == curr) {
++count;
} else {
out += std::to_string(count) + curr;
curr = s[i];
count = 1;
}
}
out += std::to_string(count) + curr; // ← 关键:补最后一段
return out;
}解压时数字解析不能用atoi硬转
压缩串形如 "12a3b",解压需把 "12" 当作整数而非逐位读取。若用 atoi 或手动遍历每个字符转数字,会错把 "12a" 拆成 1 和 2,导致输出 "aa" 而非 "aaaaaaaaaaaa"。
立即学习“C++免费学习笔记(深入)”;
正确做法:遇到数字字符就累积成字符串,遇到字母再统一转整型:
std::string rle_decompress(const std::string& s) {
std::string out;
size_t i = 0;
while (i < s.length()) {
std::string num_str;
while (i < s.length() && std::isdigit(s[i])) {
num_str += s[i++];
}
if (num_str.empty() || i >= s.length()) break;
int count = std::stoi(num_str);
char c = s[i++];
out.append(count, c);
}
return out;
}性能与内存分配陷阱
每次 out += ... 都可能触发字符串重分配。对长输入(如万级重复字符),建议预估容量:最坏情况是每个字符都不同,压缩后长度≈2×原长(每个字符配一位数计数),可用 out.reserve(2 * s.length()) 提前分配。
另外注意:
- std::stoi 在数字超 int 范围时抛异常,生产环境需加 try/catch 或用 std::from_chars(C++17)
- 若压缩目标是二进制数据(非字符串),别用 std::string 存计数+字节,改用 std::vector<std::pair<int, uint8_t>> 更安全
- RLE本身无标准格式,"3a2b" 和 "a3b2" 都有人用,团队内必须约定清楚
压缩逻辑简单,但数字解析和边界处理稍有不慎就崩;真正难的不是写出来,是让 rle_compress(rle_decompress(s)) == s 在所有 corner case 下都成立。


















