我在Scala中写了一个huffman压缩/解压缩。解码小文件时需要几秒钟,但解码较大的文件时需要很长时间。关于如何加快这一过程的任何建议?
def lookup(list:List[Int],list2:List[(Char,List[Int])]): Option[String]={
val mutableListBuffer = scala.collection.mutable.ArrayBuffer(list2: _*)
var option:Option[String]= None
for(i <- 0 until mutableListBuffer.length){
if(mutableListBuffer(i)._2 == list){
option = Some(mutableListBuffer(i)._1.toString)
}
}
option
}
/*
*Decode function for matching groups of bits in a list to characters in the HCodeMap
*@returns String
*/
def decode(acc:Int,s:String,list:(List[Int],List[(Char,List[Int])])):String ={
var s = ""
var accum = 1
val listp1 = scala.collection.mutable.ArrayBuffer(list._1: _*)
val listp2 = scala.collection.mutable.ArrayBuffer(list._2: _*)
var tupList = (listp1,listp2)
while(!tupList._1.isEmpty){
if(lookup(tupList._1.take(accum).toList,tupList._2.toList).isDefined){
println(accum)
s = s ++ lookup(tupList._1.take(accum).toList,tupList._2.toList).getOrElse("a")
Log.d("MyTAG", "de" + s)
tupList._1.remove(0,accum)
accum = accum - accum + 1
}
else{
accum = accum + 1
}
}
s
}
代码在Android设备上执行,因此使用递归不是一个有效的选项,也不是使用不可变列表。任何建议将不胜感激。再次感谢。
答案 0 :(得分:1)
这可能属于codereview,但我认为这里的代码直接等同于你的代码,没有任何转换为ArrayBuffers(这是不必要的)。列表操作相当有效,只需要删除和列表遍历,所以我认为你错误地指责不可变列表。
def lookup(list: List[Int], list2: List[(Char, List[Int])]): Option[String] =
list2.find(_._2 == list).map(_._1.toString)
/*
*Decode function for matching groups of bits in a list to characters in the HCodeMap
*@returns String
*/
def decode(s: String, list: (List[Int], List[(Char, List[Int])])): String = {
var s = ""
var accum = 1
var listp1 = list._1
val listp2 = list._2
while (!listp1.isEmpty) {
lookup(listp1.take(accum), listp2) match {
case Some(m) =>
println(accum)
s = s ++ m
Log.d("MyTAG", "de" + s)
listp1 = listp1.drop(accum)
accum = 1
case None =>
accum = accum + 1
}
}
s
}
答案 1 :(得分:1)
如果你想要它快,你的出发点是错误的。您应该直接使用位流,而不是包含一位的每个整数的整数列表。在某个地方,你浪费时间将传入的位转换为整数列表,然后浪费大量时间解码该列表。
制作快速霍夫曼解码器的一种方法是构建允许直接索引查找的解码表。选择一些位 n ,这大约是统一代码的长度。例如。如果你有256个符号,那么让我们从 n 开始为8。 (您可以稍后使用 n 来优化速度。)
现在构建一个256条目表,该表由接下来的8位输入索引。每个条目指示a)下一个代码是8位或更少,或b)下一个代码的长度是9位或更多。对于a),该表告诉您代码中的位数和它解码的符号。在这种情况下,您从流中删除那么多位并发出符号。
对于b),该表指向下一个表,用随后的位索引,以及有多少位。然后,您从流中丢弃8位并索引子表,该子表也将指示a)或b)。虽然你可能会有两个级别的表是最优的,所以子表将始终指示a),完成解码并发出符号。在这种情况下,子表的大小,即索引中的位数,是最长代码的长度减去8,它具有索引主表的8位前缀。
这些表很容易构建,并且构建只需一次多次使用,这使得构建时间非常值得。表中的条目经常重复多次。例如。一个四位代码将在基本的八位表中重复16次。
您可以对位缓冲区(整数)使用位操作,根据需要从流中提取字节,以使其加载足够的位以形成下一个索引。简单的位移会在使用时将位向下移动,输入字节上的位向上移位将在它们进入位缓冲区之前完成。
一旦完成所有工作,您可以改变 n 并使用代表性输入为解码器计时,以找到 n 的最佳值。