C++程序编写压缩器/解压器(长度-游程编码的压缩/解压+霍夫曼编码压缩/解压 (霍夫曼树))
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++程序编写压缩器/解压器(长度-游程编码的压缩/解压+霍夫曼编码压缩/解压 (霍夫曼树))相关的知识,希望对你有一定的参考价值。
输入的为本文文件(.txt),输出的为一种自定义的文件(.nz)。考虑当构成文本的字符集合为a,b,c,……,z,0,1,2,…9时,请用实例测试你的压缩/解压器。你的压缩器会不会出现抖动?(压缩后的文本比原来的还要大)。扩充构成文本的字符集合以便使它适应更一般的情况。
霍夫曼编码:根据不同符号在文本中出现的不同的频率来进行压缩编码。假设文本是由
a,u,x,z组成的字符串,若这个字符串的长度为1000,每个字符用一个字节来存储,共需1000个字节(即8000位)的空间。如果每个字符用2位二进制来编码(00=a,01=x,10=u,11=z),则用2000位二进制即可以表示1000个字符。此外,还需要一定的空间来存放编码表,可以采用如下格式来存储:
符号个数:代码1,符号1,代码2,符号2,……
符号个数及每个符号分别用8位二进制来表示,每个代码需要占用[log2(符号个数)]位二进制。因此,上例中,代码表需占用5*8+4*2=48位,压缩比为8000/2048=3.9 。利用这种编码方法,字符串aaxuaxz的压缩码为二进制串00000110000111,每个字符的编码具有相同的位数(两位)。从左到右依次从位串中取出两位,通过查编码表边可以获得原字符串,这是解压缩过程。
我们利用霍夫曼编码来实现压缩,必须:
必须获得不同字符的频率。
建立具有最小加权外部路径的二叉数(即霍夫曼树),树的外部结点用字符串中
的字符表示,外部结点的权重(weight)即为该字符出现的频率。
遍历从根到外部结点的路径得到每个字符的编码。
使用字符的编码来代替字符串中的字符。
为了方便解码,需要保存字符代码映射表或每个字符的
频率表(在保存信息为频率表的情况下,解码需要重构霍夫曼数以获得相应的编码表)。
构造霍夫曼树:首先从仅含一个外部结点的二叉树集合开始,每个外部结点代表字符串的一个不同的字符,其权重等于该字符的频率。此后不断的从集合中选择两棵具有最小权重的二叉树,并把它们合并成一棵新的二叉树,合并方法是把这两棵二叉树分别作为左右子树,然后增加一个新的根结点。新二叉树的权重为两棵子树的权重之和。这个过程一直可以持续到仅剩下一棵树为止。[二叉树的集合可以使用有序表 /优先队列(基于队列/基于堆)实现]。
编码:构造完毕霍夫曼树后,可以对从根开始到外部结点(叶子)的路径进行编码,方法是向左孩子移动时取0,向右孩子移动时取1。
对于霍夫曼编码:当文本中的字符出现的频率差别很大时,我们可以通过使用变长的编码来降低每个位串的长度。但是,怎样对使用变长编码的位串解码呢?我们可以发现:在得到的霍夫曼编码中,没有任何一个代码是另一个代码的前缀。因此与编码向匹配的实际的字符是唯一的。请用实现这样的变长策略,并验证它。
就是帮忙写这个程序啊
在 MSVC 中压缩后可能的数据损坏? (C++)
【中文标题】在 MSVC 中压缩后可能的数据损坏? (C++)【英文标题】:Possible Data corruption after compression in MSVC? (C++) 【发布时间】:2014-01-17 06:14:04 【问题描述】:我对 C++ 有点陌生,并且正在玩弄基本的压缩。我在 MSVC(Windows 7,编译为 32 位控制台程序)中编写了下面的程序,它将具有 4 个可能值的 char 数组压缩为一个字节。我已经包含了代码行来检查中间二进制值。
(以下代码很长,请见谅,唯一包含的是iostream)
程序运行时:
ABCD转换为11100100,根据我的编码表是正确的。 这会在我的系统上转换为 ASCII ý。
但是,解码后,ý 变为 11101100,解码为“ADCD”!我已经尝试了其他一些起始数组,并且损坏似乎只发生在数组中的第二个字符是“B”,然后它被更改为“D”时,或者如果有一个全是“B”的字符串"s,当备用的 "B" 变为 "D" 时。当放置在其他位置时,“B”不会损坏。
我很困惑为什么一个位会出错,并且只针对特定的序列,如果有人能给我一些提示吗?
谢谢!
K
struct CompressedChar
int firstbit;
int secondbit;
;
CompressedChar Encoder(char baseinput)
CompressedChar bitoutput;
switch (baseinput)
case 'A':
bitoutput.firstbit = 0;
bitoutput.secondbit = 0;
break;
case 'B':
bitoutput.firstbit = 1;
bitoutput.secondbit = 0;
break;
case 'C':
bitoutput.firstbit = 0;
bitoutput.secondbit = 1;
break;
case 'D':
bitoutput.firstbit = 1;
bitoutput.secondbit = 1;
break;
return bitoutput;
char Decoder(int firstbit, int secondbit)
if (firstbit == 0)
if (secondbit == 0)
return 'A';
else if (secondbit == 1)
return 'C';
else if (firstbit == 1)
if (secondbit == 0)
return 'B';
else if (secondbit = 1)
return 'D';
return '0';
int main()
char a[4] = 'A', 'B', 'C', 'D';
char output;
for (int i = 0; i < 8; i += 2)
CompressedChar bitoutput;
bitoutput = Encoder(a[(i/2)]);
std::cout << bitoutput.firstbit;
std::cout << bitoutput.secondbit;
if (bitoutput.firstbit == 1)
output |= (1 << i);
else if (bitoutput.firstbit == 0)
output &= ~(1 << i);
if (bitoutput.secondbit == 1)
output |= (1 << (i + 1) );
else if (bitoutput.firstbit == 0)
output &= ~(1 << (i + 1));
std::cout << std::endl << output << std::endl;
char b[4];
int temp1, temp2;
for (int i = 0; i < 8; i += 2)
temp1 = (output >> i) & 1;
temp2 = (output >> (i + 1)) & 1;
std::cout<< temp1;
std::cout<< temp2;
b[i/2] = Decoder(temp1, temp2);
std::cout<< std::endl;
for (int j = 0; j < 4; j ++)
std::cout << b[j];
std::cout << std::endl;
return 0;
【问题讨论】:
【参考方案1】:这是因为它被初始化为 0xCC。您也可能在网上犯了一个错误,上面写着“else if (bitoutput.firstbit == 0)”应该是 secondbit。还要使输出 unsigned char 安全/清晰。
【讨论】:
谢谢!固定的!我知道我一定是做错了什么……尽管如此,我仍然不明白为什么这些错误只针对“B”字符。 这是因为它被初始化为 0xCC。您也可能在网上犯了一个错误,上面写着“else if (bitoutput.firstbit == 0)”应该是 secondbit。还要使输出 unsigned char 安全/清晰。以上是关于C++程序编写压缩器/解压器(长度-游程编码的压缩/解压+霍夫曼编码压缩/解压 (霍夫曼树))的主要内容,如果未能解决你的问题,请参考以下文章