P10 - 游程编码

2026-09-07 00:00    #Haskell   #99题   #列表  

P10 - 游程编码

Run-length encoding of a list

官方模块: Problems.P10 核心函数: encode


← P09 将连续重复元素打包成子列表 | P11 改进的游程编码 →



← P09 将连续重复元素打包成子列表 | P11 改进的游程编码 →


题目描述

利用 P09 的 pack 函数实现游程编码(run-length encoding):将连续重复的元素编码为 (元素, 出现次数) 元组。

函数签名

1encode :: Eq a => [a] -> [(Int, a)]

输出格式为 [(出现次数, 元素)]

思路

题目明确提示用 P09 的 pack 来实现:

  1. pack 把连续重复元素打包成子列表
  2. 对每个子列表,取其长度(出现次数)和第一个元素
  3. 组合成 (count, element) 元组

实现

方法一:利用 pack

1encode :: Eq a => [a] -> [(Int, a)]
2encode xs = [(length group, head group) | group <- pack xs]

列表推导式:每个 group 来自 pack xs,取 length group 作为出现次数,head group 作为元素。

也可以用 map 写:

1encode :: Eq a => [a] -> [(Int, a)]
2encode = map (\group -> (length group, head group)) . pack

方法二:自己实现 pack + encode(不依赖外部函数)

1encode :: Eq a => [a] -> [(Int, a)]
2encode [] = []
3encode (x:xs) = let (group, rest) = span (== x) xs
4                in (1 + length group, x) : encode rest

不依赖 pack,直接用 span 边分组边编码。每步切分出与 x 相等的连续段,个数是 1 + length group

方法三:使用 group 标准库

1import Data.List (group)
2
3encode :: Eq a => [a] -> [(Int, a)]
4encode = map (\g -> (length g, head g)) . group

Data.List.group 等价于 P09 的 pack

编码与压缩

游程编码是数据压缩中最基础的方法。对于有大量连续重复的数据(如图像的二值化表示),压缩比非常可观:

1encode "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB"
2-- [(12,'W'),(1,'B'),(12,'W'),(3,'B'),(24,'W'),(1,'B')]

12 个 ‘W’ 编码为 (12, 'W'),一个字符加一个整数,比存 12 个字符省得多。

测试

 1>>> encode "aaaabccaadeeee"
 2[(4,'a'),(1,'b'),(2,'c'),(2,'a'),(1,'d'),(4,'e')]
 3
 4>>> encode []
 5[]
 6
 7>>> encode [1,1,2,2,2,3]
 8[(2,1),(3,2),(1,3)]
 9
10>>> encode "a"
11[(1,'a')]

参考


← P09 将连续重复元素打包成子列表 | P11 改进的游程编码 →