元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
算法基础
▶
复杂度分析
时间复杂度
空间复杂度
渐进符号
▶
算法思想
分治法
贪心算法
回溯法
概率算法
枚举算法
递推算法
递归算法
动态规划
分支限界法
模拟算法
▶
算法分析
正确性证明
性能优化
算法比较
▶
搜索算法
▶
基本搜索
顺序搜索
二分搜索
插值搜索
▶
图搜索
深度优先搜索
广度优先搜索
启发式搜索
▶
高级搜索
双向搜索
A*算法
模式匹配
▶
排序算法
▶
比较类排序
冒泡排序
快速排序
归并排序
插入排序
选择排序
▶
非比较类排序
计数排序
基数排序
桶排序
▶
高级排序
堆排序
希尔排序
外部排序
拓扑排序
▶
图论算法
▶
图的表示
邻接矩阵
邻接表
边集数组
▶
最短路径
Dijkstra算法
Floyd算法
Bellman-Ford算法
最短路径概述
▶
生成树
Prim算法
Kruskal算法
并查集
最小生成树
▶
图的连通性
强连通分量
割点与桥
双连通分量
欧拉路径
▶
动态规划
▶
基础概念
最优子结构
重叠子问题
状态转移方程
▶
经典问题
背包问题
最长公共子序列
编辑距离
▶
优化技巧
空间优化
状态压缩
区间动态规划
▶
字符串算法
▶
字符串匹配
KMP算法
Boyer-Moore算法
Sunday算法
▶
字符串处理
字典树
后缀数组
字符串哈希
▶
压缩算法
游程编码
Huffman编码
LZ77算法
发布时间:
2025-03-21 20:04
↑
☰
# 游程编码 游程编码(Run-Length Encoding,简称RLE)是一种简单但有效的无损数据压缩算法。它通过记录连续重复字符的计数来压缩数据,特别适用于具有大量重复字符的数据。 ## 基本概念 ### 定义 游程编码的基本思想是: - 将连续出现的相同字符用一个计数值和该字符来表示 - 计数值表示该字符连续出现的次数 - 非重复字符可以视为计数值为1的情况 ### 示例 原始字符串:"AABBBCCCC" 编码结果:"2A3B4C" 解释: - "AA" → "2A"(2个A) - "BBB" → "3B"(3个B) - "CCCC" → "4C"(4个C) ## 实现原理 ### 基本实现 ```go // 游程编码结构 type RunLength struct { data string } // 创建新的游程编码器 func NewRunLength(data string) *RunLength { return &RunLength{data: data} } // 编码 func (rl *RunLength) Encode() string { if len(rl.data) == 0 { return "" } var result strings.Builder count := 1 current := rl.data[0] for i := 1; i < len(rl.data); i++ { if rl.data[i] == current { count++ } else { result.WriteString(strconv.Itoa(count)) result.WriteByte(current) current = rl.data[i] count = 1 } } // 处理最后一组字符 result.WriteString(strconv.Itoa(count)) result.WriteByte(current) return result.String() } // 解码 func (rl *RunLength) Decode(encoded string) string { if len(encoded) == 0 { return "" } var result strings.Builder count := 0 for i := 0; i < len(encoded); i++ { if encoded[i] >= '0' && encoded[i] <= '9' { count = count*10 + int(encoded[i]-'0') } else { // 重复写入字符 for j := 0; j < count; j++ { result.WriteByte(encoded[i]) } count = 0 } } return result.String() } ``` ### 高级特性 ```go // 支持二进制数据的游程编码 type BinaryRunLength struct { data []byte } // 编码二进制数据 func (brl *BinaryRunLength) Encode() []byte { if len(brl.data) == 0 { return nil } result := make([]byte, 0) count := 1 current := brl.data[0] for i := 1; i < len(brl.data); i++ { if brl.data[i] == current && count < 255 { count++ } else { result = append(result, byte(count), current) current = brl.data[i] count = 1 } } result = append(result, byte(count), current) return result } // 解码二进制数据 func (brl *BinaryRunLength) Decode(encoded []byte) []byte { if len(encoded) == 0 || len(encoded)%2 != 0 { return nil } result := make([]byte, 0) for i := 0; i < len(encoded); i += 2 { count := int(encoded[i]) value := encoded[i+1] for j := 0; j < count; j++ { result = append(result, value) } } return result } ``` ## 应用场景 ### 图像压缩 ```go // 图像游程编码 type ImageRunLength struct { width int height int pixels []byte } // 编码图像数据 func (irl *ImageRunLength) Encode() []byte { if len(irl.pixels) == 0 { return nil } result := make([]byte, 0) count := 1 current := irl.pixels[0] // 添加图像尺寸信息 result = append(result, byte(irl.width>>8), byte(irl.width)) result = append(result, byte(irl.height>>8), byte(irl.height)) for i := 1; i < len(irl.pixels); i++ { if irl.pixels[i] == current && count < 255 { count++ } else { result = append(result, byte(count), current) current = irl.pixels[i] count = 1 } } result = append(result, byte(count), current) return result } ``` ### 数据传输 ```go // 网络传输优化的游程编码 type NetworkRunLength struct { data []byte maxRun int // 最大运行长度 minRun int // 最小运行长度(小于此长度不压缩) } // 编码数据包 func (nrl *NetworkRunLength) EncodePacket() []byte { if len(nrl.data) == 0 { return nil } result := make([]byte, 0) i := 0 for i < len(nrl.data) { // 计算运行长度 count := 1 current := nrl.data[i] for i+count < len(nrl.data) && nrl.data[i+count] == current && count < nrl.maxRun { count++ } // 判断是否值得压缩 if count >= nrl.minRun { result = append(result, 0xFF) // 标记为压缩数据 result = append(result, byte(count), current) i += count } else { // 不压缩的数据 result = append(result, current) i++ } } return result } ``` ## 性能分析 ### 时间复杂度 1. 编码 - 最好情况:O(n) - 最坏情况:O(n) - 平均情况:O(n) 2. 解码 - 最好情况:O(n) - 最坏情况:O(n) - 平均情况:O(n) ### 空间复杂度 1. 编码后大小 - 最好情况:O(n/k),k为平均运行长度 - 最坏情况:O(2n),当数据完全不重复时 - 平均情况:取决于数据重复性 2. 内存使用 - 编码:O(1)或O(n),取决于实现 - 解码:O(n) ### 压缩效率 1. 影响因素 - 数据重复性 - 运行长度分布 - 编码方案选择 2. 优化方向 - 可变长度编码 - 混合编码策略 - 预处理优化 ## 实践建议 ### 使用场景选择 1. 适用场景 - 二值图像 - 简单图形 - 重复性强的数据 2. 不适用场景 - 随机数据 - 自然图像 - 复杂文本 ### 实现技巧 1. 编码优化 - 使用缓冲区 - 批量处理 - 并行编码 2. 解码优化 - 预分配内存 - 流式处理 - 错误检测 ## 总结 1. 优点 - 实现简单 - 解码快速 - 无损压缩 2. 缺点 - 压缩比有限 - 不适合随机数据 - 可能导致数据膨胀 3. 应用建议 - 根据数据特点选择 - 考虑混合压缩策略 - 注意边界处理