当前位置: 首页 > 知识库问答 >
问题:

为什么Huffman树代码需要无符号字符

柴赞
2023-03-14

我正在尝试创建一个霍夫曼树,我看到的问题对我来说很奇怪,它如下:

给定以下数据结构

struct huffman
{
    unsigned char sym;              /* symbol */
    struct huffman *left, *right;   /* left and right subtrees */
};

编写一个程序,该程序将二进制文件的名称作为唯一参数,构建该文件的霍夫曼树,假设原子(基本符号)是8位无符号字符,并打印树和字典。
分配必须使用 malloc() 以外的任何东西来完成,排序可以使用 qsort() 来完成。

这里让我感到困惑的是,要编写一个程序来创建霍夫曼树,我们只需要做以下事情:

  1. 我们需要取一个频率数组(可以是Farray[]={……}
  2. 对其进行排序并添加两个最小的节点以形成一棵树,直到它不留下最后一个节点(即头部)

现在问题就在这里:为什么以及在哪里需要这些无符号的字符数据?(这个问题想要什么类型的无符号字符数据,我认为只有频率就足以显示霍夫曼树)?

共有3个答案

澹台展鹏
2023-03-14

通常数据压缩分为两个大步骤;给定数据流:

  • 评估给定符号出现在流中的概率,换句话说,您评估符号在数据集中出现的频率
  • 一旦你研究了这些事件并创建了与概率相关的符号的表,你需要根据它们的概率对符号进行编码,为了实现这个魔法,你创建了一个字典,原来的符号通常只是被另一个尺寸小得多的符号替换,尤其是对于数据集中经常使用的符号,字典会跟踪编码和解码阶段的这种替换。霍夫曼给了你一个算法来自动化这个过程,并获得相当好的结果。

在实践中,它比这更复杂一些,因为涉及树,但主要目的始终是构建字典。

这里有完整的教程。

柴琦
2023-03-14

我这样做已经有一段时间了,但我认为需要生成的“字典”来编码数据,而“树”用于解码它。当然,你总是可以从另一个构建一个。

解码时,您遍历树(左/右,根据连续的输入位),当您击中终端节点(空指针)时,节点中的“sym”就是产出值。

任长卿
2023-03-14

如果您纯粹想显示树的形状,那么是的,您只需要构建它。然而,为了使它有任何用途,您需要知道每个节点代表什么原始符号。

假设您的输入符号是[ABCD]。想象中的霍夫曼树/字典可能如下所示:

         ( )
        /   \              A = 1
      ( )   (A)            B = 00
     /   \                 C = 010
   (B)   ( )               D = 011
        /   \
      (C)   (D)

如果不存储sym,它看起来像这样:

         ( )
        /   \              A = ?
      ( )   ( )            B = ?
     /   \                 C = ?
   ( )   ( )               D = ?
        /   \
      ( )   ( )

不是很有用,是吗?

编辑2:计划中缺少的步骤是步骤0:从文件构建频率数组(不知何故,我错过了您也不需要实际编码文件)。这不是实际的霍夫曼算法本身的一部分,我找不到一个像样的例子来链接,所以这里有一个粗略的想法:

FILE *input = fopen("inputfile", "rb");
int freq[256] = {0};
int c;
while ((c = fgetc(input)) != EOF)
    freq[c]++;
fclose(input);

/* do Huffman algorithm  */
...

现在,这仍然需要改进,因为它既不使用malloc()也不将文件名作为参数,但这不是我的家庭作业;)

 类似资料:
  • 问题内容: 据我所知,如果字体包含空格,则需要使用双引号或单引号,例如: 但是在Google字体上,我也看到了 有些人甚至这样使用它: 我觉得这很奇怪,因为以下方法也可以: 那么CSS中字体名称周围引号的正确用法是什么? 问题答案: 您可以随时把一个特定的字体系列名称在引号,双或单,所以,和是等价的。仅CSS定义的通用字体系列之类的名称必须不带引号。 与流行的看法相反,字体名称由空格分隔的名称组成

  • 为什么在C 11中无符号短*无符号短转换为int? int太小,无法处理这行代码显示的最大值。 MinGW 4.9.2溢流 因为(来源) USHRT_MAX=65535 (2^16-1)或更大* INT_MAX=32767 (2^15-1)或更大* 和(2^16-1)*(2^16-1)=~2^32。 这个解决方案会有什么问题吗? 此程序 给出输出 在…上 两者都有 这证明在这些编译器上,被转换为。

  • 我对字符编码的概念很困惑。 什么是Unicode、GBK等?编程语言如何使用它们? 我需要费心去了解他们吗?有没有一种更简单或更快的编程方法,而不必麻烦自己?

  • 使用oAuth 2.0,在“授权代码”授权授予中,我首先调用“/授权”,获取代码,然后在对“/令牌”的调用中使用该代码来获取访问令牌。 我的问题:为什么这是流?我想这是出于安全原因,但我想不出来。为什么实现是这样的,而不是在第一次调用(“/authorize”)后立即获取访问令牌? 为什么我们需要这个代码?

  • 我试图理解为什么我们需要通配符——Java泛型中的问号,为什么我们不能使用普通的单字符t或E等作为类型?请看以下示例: 结果是一样的,尽管通配符版本更简洁。这是唯一的好处吗?

  • null 我理解Mono是一个由0或1个元素组成的流和Flux是一个由0或N个元素组成的流之间的区别。 既然Mono和Flush都在实现,为什么我们需要这两种类型,为什么不对所有内容都使用Flux呢?