我寻找一种算法,让我将一个输入的比特序列表示为字母('a'...'z'),这是一个最小的事情,这样比特流就可以从字母中重新生成,而不会持有记忆中的整个序列。
也就是说,给定一个外部位源(每次读取返回一个实际上随机的位),以及用户输入多个位,我想打印出可以代表这些位的最小字符数。
理想情况下,应该有参数化 - 在需要浪费之前,内存与最大位数之比。
效率目标 - 与位的基数26表示相同的字符数。
非解决方案:
如果存在足够的存储空间,请存储整个序列并使用大整数MOD 26操作。
将每9位转换为2个字符 - 这似乎不是最理想的,浪费了25%的字母输出信息容量。
答案 0 :(得分:8)
如果为每个字母分配不同的位数,则应该能够准确编码允许的26个字母中的位而不会浪费任何位。 (这很像霍夫曼代码,只有预先构建的平衡树。)
将位编码为字母:累积位,直到您完全匹配查找表中的一个位代码。输出那个字母,清除位缓冲区,然后继续。
将字母解码为位:对于每个字母,输出表中的位序列。
在代码中实现是留给读者的练习。 (或者对我来说,如果我以后觉得无聊的话。)
a 0000
b 0001
c 0010
d 0011
e 0100
f 0101
g 01100
h 01101
i 01110
j 01111
k 10000
l 10001
m 10010
n 10011
o 10100
p 10101
q 10110
r 10111
s 11000
t 11001
u 11010
v 11011
w 11100
x 11101
y 11110
z 11111
答案 1 :(得分:6)
将每个47位的块转换为基数为26的10位数。这使您的效率超过99.99%。
这种方法以及像Huffman这样的其他方法需要填充机制来支持可变长度输入。这引入了一些效率低下的问题,即输入时间越长,效率越低。
在比特流的末尾,添加一个额外的1
位。这必须在所有情况下完成,即使比特流的长度是47的倍数。在编码输出的最后一个块中可以跳过任何“零”值的高位字母。
对字母进行解码时,可以用“零”字母填写截断的最后一个块,并将其转换为47位的基本2表示。最后的1
位不是数据,而是标记位流的结束。
答案 2 :(得分:3)
Huffman coding可以成为您想要的吗?它是一种压缩算法,几乎可以用最少的浪费位表示任何信息。
答案 3 :(得分:3)
零浪费将是每个字母的log_2(26)位。如前所述,您可以通过读取47位并将其转换为10个字母来达到4.7。但是,通过将每14位转换为3个字符,可以达到4.67。这具有适合整数的优点。如果您有存储空间并且运行时间很重要,则可以创建一个包含17,576个条目的查找表,将可能的14位映射为3个字母。否则,您可以执行mod和div操作来计算3个字母。
number of letters number of bits bits/letter
1 4 4
2 9 4.5
3 14 4.67
4 18 4.5
5 23 4.6
6 28 4.67
7 32 4.57
8 37 4.63
9 42 4.67
10 47 4.7
答案 4 :(得分:1)
你使用的任何解决方案都是空间效率低的,因为26不是2的幂。就算法而言,我宁愿使用查找表而不是每个系列的动态计算。 9位。您的查找表将长512个条目。
答案 5 :(得分:1)
如果您希望每个字母的二进制占用空间具有相同的大小,则Arithmetic Encoding将给出最佳解决方案。但是,它不会达到4.5比特/字符的平均表示的目标。鉴于26个不同的字符(不包括空格等)4.7,如果不使用可变长度编码(例如Huffman,请参阅Jaegers的答案)或其他压缩算法,4.7将是最好的。
一个次优的,虽然更简单的解决方案可能是找到一个可行数量的字符以适应一个大整数。例如,如果你在每6个charachter块中形成一个32位整数(可能是26 ^ 6< 2 ^ 32),那么你使用5.33 bits / char。实际上,你甚至可以将13个字母组合成64位整数(4.92位/字符)。这非常接近最佳解决方案,并且仍然相当容易实现。由于缺少许多编程语言中的原生支持,使用大于64位的整数可能会很棘手。
如果你想要更好的文本压缩率,你肯定也应该研究基于字典的压缩算法,比如LZW或Deflate。