【问题标题】:Convention for Huffman Coding霍夫曼编码公约
【发布时间】:2015-11-16 03:18:48
【问题描述】:

是否有为特定字母生成 Huffman 编码的约定?结果编码似乎取决于您将“0”分配给左孩子还是右孩子,以及您如何确定哪个符号将进入左树。

Wikipedia 说:

按照惯例,位'0'表示跟随左孩子 而位'1'代表跟随右孩子。

所以这是方差前半部分的答案。但是,我找不到下半场的任何约定。我会假设像使概率较低的节点在左侧,但是在线的几个示例霍夫曼树不这样做。

例如:

那么对于左右节点的分配是否有约定,还是取决于实现?

如果这是重复的,我深表歉意,但我无法找到答案。

【问题讨论】:

  • 我认为唯一的“约定”是我们选择的“标准”算法,即 gzip。
  • 那样的话,有关系吗?是否会出现这样一种情况,即选择一个会产生比选择另一个效率低的代码? (也许这应该是一个新问题)

标签: huffman-code


【解决方案1】:

是的,事实上有。与其说是互操作性的约定,不如说是编码效率的约定。它被称为Canonical Huffman,其中代码按从最短代码到最长代码的数字顺序分配,并且在单个代码长度内,它们按符号上的字典顺序分配。这允许仅传输每个符号的代码长度,而不是整个树结构。

通常所做的只是使用霍夫曼算法树来确定每个符号的位数。然后丢弃树。位值永远不会分配给分支。然后使用上面的顺序直接从长度构建代码。

【讨论】:

  • 有道理。谢谢
【解决方案2】:

看看

        class Nodo{
      constructor(v=null,f=null,l=null,r=null){
            this.f=f
            this.v=v
            this.l=l
            this.r=r
          }
      }
        function EnCrypt(text){
            let lista=[]
            for(let i=0;i<text.length;i++){//Create the list with the appearances 
                !lista.find(e => e.v===text[i]) && lista.push(new Nodo(text[i],(text.match(new RegExp(text[i],"g")) || []).length))
            }
            lista=lista.sort((a,b)=>a.f-b.f)//Order from smallest to largest
            //----------------------------------------------------
            function createNew(){//Create the tree
                let nodos=lista.splice(0,2)
                lista.push(new Nodo(null,nodos[0].f+nodos[1].f,nodos[0],nodos[1]))
                if(lista.length==1)return lista
                createNew()
            }createNew()
          ///-----------------------------------------------
            let Arbol=lista[0]
            function Codigo(nodo,c=""){//recursively traverse the tree 
                if(!nodo.l && !nodo.r)return [nodo.v,c]
                return Codigo(nodo.l,c+"0")+";"+Codigo(nodo.r,c+"1")
            }
           //-----------------------------------------------
            const codigo=(Codigo(Arbol)).split(";")
            let finish=""
            text.split("").map(t=>{
                codigo.map(e => {
                    if(e.split(",")[0]==t)finish+=e.split(",")[1]
                })
            })
            return {
                cod:finish,
                dicc:codigo
            }
        }
        function DeCrypt(key,res=""){
            let {cod,dicc}=key
            let temp=""
            for(let i=0;i<=cod.length;i++){
                temp+=cod.substr(i,1)
               dicc.map((d)=>{
                    d=d.split(",")
                    if(temp==d[1]){
                        res+=d[0]
                        temp=""
                        cod=cod.substr(i)
                        i=0
                    }
                })
            }
            return res
        }
        function Huffman(){
                const text=document.querySelector("#newValue").value
                const comp= EnCrypt(text)
                document.querySelector(".res").innerHTML=JSON.stringify(comp,null, 4)
            }
        function HuffmanDecode(){
                const text=JSON.parse(document.querySelector("#huffman").value)
                const comp= DeCrypt(text)
                document.querySelector(".res2").innerHTML=comp
            }
<h1></h1>
<input type="text"
       placeholder="set value (min 2 chars)" id="newValue">
<button onclick="Huffman()">Go</button>
<div class="res" style="white-space: pre-wrap;"></div>

<input type="text" placeholder="paste the result from above" id="huffman"><button onclick="HuffmanDecode()">decode</button>
 <div class="res2" style="white-space: pre-wrap;"></div>

【讨论】:

  • 感谢您在这里分享代码。也许我遗漏了一些东西,但这如何解决 OP 关于 0 和 1 孩子的不同含义的问题?
  • 节点根据它们在列表中的权重从低到高排序,因此,权重最低的总是左边的,在树中它将是左孩子(0)右孩子( 1),如果我错了,对不起
  • 我把这个问题解释为“你如何将树分配给左子树或右子树有关系吗?”而不是“你如何分配它们?”但也许那是我误读了。
  • 而不仅仅是代码 sn-p 您应该解释它如何回答 OP 的问题
猜你喜欢
  • 1970-01-01
  • 2010-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多