【问题标题】:Huffman Decoding Compressed File霍夫曼解码压缩文件
【发布时间】:2023-03-14 15:02:02
【问题描述】:

我有一个程序可以根据在文本输入文件中读取的 ASCII 字符频率生成 Huffman 树。霍夫曼代码存储在 256 个元素的字符串数组中,如果字符未被读取,则为空字符串。该程序还对输出文件进行编码和压缩。

我现在正在尝试解压缩和解码作为输入文件打开的当前输出文件,并且新的输出文件将具有与原始文本输入文件相同的解码消息。

我对这部分作业的思考过程是从我创建的编码函数向后工作,一次读取 8 位,并通过更新最初是空字符串的变量(字符串 n)以某种方式解码消息,通过霍夫曼树的递归,直到我得到一个输出到输出文件的代码。

我目前已经启动了这个函数,但是我被卡住了,我正在寻找一些指导来编写我当前的 decodeOutput 函数。感谢所有帮助。
我完成的encodedOutput函数和decodeOutput函数如下:

(对于encodedOutput函数,fileName为输入文件参数,fileName2为输出文件参数)

(对于decodeOutput函数,fileName2为输入文件参数,fileName 3为输出文件参数)

code[256] 是这两个函数的参数,并保存在原始输入文件中读取的每个唯一字符的 Huffman 代码,例如,在输入文件中读取的字符“H”可能具有代码“111”在传递给函数时存储在 code[72] 的代码数组中。

void encodeOutput(const string & fileName, const string & fileName2, string code[256]) {
    ifstream ifile;//to read file
    ifile.open(fileName, ios::binary);
    if (!ifile) //to check if file is open or not
    {
        die("Can't read again");
    }
    ofstream ofile;
    ofile.open(fileName2, ios::binary);
    if (!ofile) {
        die("Can't open encoding output file");
    }
    int read;
    read = ifile.get();//read one char from file and store it in int
    char buffer = 0, bit_count = 0;
    while (read != -1) {
        for (unsigned b = 0; b < code[read].size(); b++) { // loop through bits (code[read] outputs huffman code)
            buffer <<= 1;
            buffer |= code[read][b] != '0'; 
            bit_count++;
            if (bit_count == 8) {
                ofile << buffer;
                buffer = 0;
                bit_count = 0;
            }
        }
        read = ifile.get();
    }

    if (bit_count != 0)
        ofile << (buffer << (8 - bit_count));

    ifile.close();
    ofile.close();
}

//Work in progress
void decodeOutput(const string & fileName2, const string & fileName3, string code[256]) {
    ifstream ifile;
    ifile.open(fileName2, ios::binary);
    if (!ifile)
    {
        die("Can't read again");
    }
    ofstream ofile;
    ofile.open(fileName3, ios::binary);
    if (!ofile) {
        die("Can't open encoding output file");
    }
    string n = ""; 
    for (int c; (c = ifile.get()) != EOF;) {
        for (unsigned p = 8; p--;) {
            if ((c >> p & 1) == '0') { // if bit is a 0

            }
            else if ((c >> p & 1) == '1') { // if bit is a 1

            }
            else { // Output string n (decoded character) to output file
              ofile << n;
            }
        }
    }
}

【问题讨论】:

  • 你需要将你的霍夫曼代码放入树中,然后使用你读取的位来遍历树
  • 参数“code”是什么,举个例子
  • code[256] 是这两个函数的参数,并保存在原始输入文件中读取的每个唯一字符的霍夫曼代码,例如在输入文件中读取的字符“H”可能在将代码传递给函数时,将代码“111”存储在代码[72]的代码数组中。
  • 如果您无法访问原始文件,如何构建霍夫曼代码?你是单独保存的吗?
  • 是的,你需要建一棵树来解码

标签: c++ data-structures visual-studio-2017 huffman-code


【解决方案1】:

如果您使用原始霍夫曼树来构建码本,解码会更容易。但假设您只有密码本(即string code[256]),但没有原始霍夫曼树。您可以执行以下操作:

  • 将码本分成不同长度的码字组。假设码本由 n 个不同长度的码字组成: L01 n-1 .
  • 从输入文件中读取(但不消耗)k 位,k 从 L0 增加到 Ln-1,直到找到两者之间的匹配对于某些 i,输入 k 位和长度为 k = Li 的码字。
  • 输出匹配码字对应的8位字符,并消耗输入文件中的k位。
  • 重复直到输入文件中的所有位都用完。

如果码本构造正确,并且您总是查找长度增加的码字,那么您永远不会找到无法找到匹配码字的输入位序列。

实际上,就霍夫曼树等价而言,每次你将 k 个输入比特与一组长度为 k 的码字进行比较时,你都是在检查树级别 k 的叶子是否包含输入匹配码字;每次你将 k 增加到下一个更长的代码字组时,你就沿着树走到更高的级别(比如 level-0 是根)。

【讨论】:

  • 我部分理解了上述步骤。我是否将代码字保存在自己的数组中,然后在读取位时循环遍历它?
  • 有多种存储长度分区码字的方法。您可以使用map&lt;int, set&lt;int&gt;&gt;,它将每个(有效)码字长度映射到一组码字索引(这将是码字各自的字节值)。然后,您将从最短长度(map 的最小密钥 k)开始扫描,从输入文件中读取 k 位,并将这 k 位与从密钥 k 映射的 set 中的码字进行比较。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多