Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/358.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java源代码生成中的哈夫曼码译码器_Java_Performance_Parsing_Huffman Code - Fatal编程技术网

Java源代码生成中的哈夫曼码译码器

Java源代码生成中的哈夫曼码译码器,java,performance,parsing,huffman-code,Java,Performance,Parsing,Huffman Code,我想用Java创建一个快速的哈夫曼代码解码器,因此考虑查找表。由于这些表占用内存,并且我们使用Java代码来导航和访问这些表,因此可以轻松(或不)编写一个表示相同表的程序/方法 这种方法的问题是,我不知道什么是最好的策略。我知道这与缓存和分支预测中的内容有很大关系。此外,开关盒实现意味着实际的ASM超出了我的能力范围。如果我有一个内存中的查找表(或它的层次结构),我将能够简单地跳入和跳出,但出于我的目的,我怀疑该表将适合缓存 因为我实际上遍历一棵树,所以可以像else语句需要一定数量的比较语句那

我想用Java创建一个快速的哈夫曼代码解码器,因此考虑查找表。由于这些表占用内存,并且我们使用Java代码来导航和访问这些表,因此可以轻松(或不)编写一个表示相同表的程序/方法

这种方法的问题是,我不知道什么是最好的策略。我知道这与缓存和分支预测中的内容有很大关系。此外,开关盒实现意味着实际的ASM超出了我的能力范围。如果我有一个内存中的查找表(或它的层次结构),我将能够简单地跳入和跳出,但出于我的目的,我怀疑该表将适合缓存

因为我实际上遍历一棵树,所以可以像else语句需要一定数量的比较语句那样实现它,但是对于每个比较语句,它都需要额外的二进制操作

因此,存在以下选项:

  • 使用内存中查找表的通用算法
  • 决策树的If/else表示法
  • 使用小的switch语句进行If/else表示,以找到正确的符号组(相同的位模式长度)(If语句越少,代码可能越多)
  • Switch语句表示的代码
写作和基准测试是相当棘手的,所以任何最初的想法都是很好的

另一个问题是位的顺序。最高有效位总是在第一位,这意味着它以相反的顺序存储

如果你的树是A=0,B=10,C=11来写BAC,那么它实际上是01+0+11(加上附加的意思)

所以实际上,代码必须以相反的顺序编写。对组使用if/else或switch方法不会有问题,因为屏蔽位很简单,而且位的反转也很简单,但它会失去从屏蔽中获取组内索引的想法,因为按相反的位顺序添加和删除具有不同的含义,并且不可能进行简单的查找

反转位是一个代价高昂的操作(我使用4位查找表),不会超过二进制操作的性能惩罚

但在移动中反转位更适合这种情况,每一位需要四个操作(上移、屏蔽、添加和下移输入)。由于我提前读取位,所有这些操作都将在寄存器中完成,因此它们可能只需要几个周期

通过这种方式,我可以使用switch、sub和if找到正确的符号组,并返回这些符号组

所以最后我需要建议。由于我的代码是全球语言处理,他们可以硬连线(即在源代码)

我想知道像Antll这样的解析器生成器用什么来表达这些决策。因为它们也可以根据输入符号进行切换或if/else,这可能会给我一个线索

[更新]

我发现了一种简化方法,它避免了反向位问题,但仍然增加了每组的成本。因此,我最终按照要遍历的组的顺序写入位。因此,我不需要对每个位进行四次修改,而是对每个组进行四次修改(不同的位长度)

对于每组,我们有: 1.第一个元素的值、大小(以及该组中最后一个元素的值)

因此,对于每个组,算法如下所示: 1.读取mbits并与当前读取值合并。 2.将该值与该组的最后一个值进行比较,如果该值不在组外,则该值是否在该组内较小。->阅读下一步 3.如果在组内,则可以访问值数组或使用switch语句

这是完全通用的,可以在没有循环的情况下使用,从而提高效率。此外,如果检测到组,则代码的位长度是已知的,并且可以从源代码中使用这些位,因为代码可以向前看(从流中读取)

[更新2]

要访问实际值,可以使用按组分组的单个大型元素数组。由于组对组的可能性降低,因此很可能有很大一部分适合二级或一级缓存,从而加快了访问速度

或者使用switch语句

[更新3]

根据开关的情况,编译器生成表开关或查找开关。查找开关的复杂性为O(log n),并存储键、jmp偏移量对,这是不可取的。因此,检查组更适合于if/else

tableswitch本身只使用跳转偏移量表,它只需要substract、compare、access和jmp来到达目标,而不是必须对常量执行返回值

因此,表访问看起来更有希望。此外,为了避免不必要的跳转,每个组可能包含访问和返回组符号表的逻辑。将所有内容存储在一个大表中是很有希望的,因为每个符号可能是int或short,而我的代码通常最多只有1000到4000个符号,这使得它实际上很短


我将检查1-模式是否能让我有机会以更好的方式存储和访问掩码,允许二进制搜索正确的组,而不是在O(n)中前进,甚至可能在处理过程中避免任何移位操作。

我无法理解你在(long)中写的大部分内容问题,但有一个简单的方法

我们将从一个表开始。假设您的最长哈夫曼代码是15位。(事实上,deflate将其哈夫曼代码的大小限制为15位。)然后构建一个包含32768个条目的表,其中每个条目是下一个代码中的位数,以及该代码的符号。对于小于15位的代码,表中有多个条目用于同一代码。例如,如果代码为10010110(7位)对于符号“C”,那么表xxxxxxxx 10010110的所有索引都有相同的内容。这些条目都有{7,'C'}

然后从流中获取15位,并在表中查找下一个代码