手机号段对应地区编码_漫画:“哈夫曼编码” 是什么鬼?
在上一期,我們介紹了一種特殊的數(shù)據(jù)結(jié)構(gòu) “哈夫曼樹”,也被稱為最優(yōu)二叉樹。沒看過的小伙伴可以點(diǎn)擊下方鏈接:
漫畫:什么是 “哈夫曼樹” ?
那么,這種數(shù)據(jù)結(jié)構(gòu)究竟有什么用呢?我們今天就來揭曉答案。
計(jì)算機(jī)系統(tǒng)是如何存儲(chǔ)信息的呢?
計(jì)算機(jī)不是人,它不認(rèn)識(shí)中文和英文,更不認(rèn)識(shí)圖片和視頻,它唯一“認(rèn)識(shí)”的就是0(低電平)和1(高電平)。
因此,我們?cè)谟?jì)算機(jī)上看到的一切文字、圖像、音頻、視頻,底層都是用二進(jìn)制來存儲(chǔ)和傳輸?shù)摹?/p>
從狹義上來講,把人類能看懂的各種信息,轉(zhuǎn)換成計(jì)算機(jī)能夠識(shí)別的二進(jìn)制形式,被稱為編碼。
編碼的方式可以有很多種,我們大家最熟悉的編碼方式就屬ASCII碼了。
在ASCII碼當(dāng)中,把每一個(gè)字符表示成特定的8位二進(jìn)制數(shù),比如:
顯然,ASCII碼是一種等長編碼,也就是任何字符的編碼長度都相等。
為什么這么說呢?讓我們來看一個(gè)例子:
假如一段信息當(dāng)中,只有A,B,C,D,E,F這6個(gè)字符,如果使用等長編碼,我們可以把每一個(gè)字符都設(shè)計(jì)成長度為3的二進(jìn)制編碼:
如此一來,給定一段信息 “ABEFCDAED”,就可以編碼成二進(jìn)制的 “000 001 100 101 010 011 000 100 011”,編碼總長度是27。
但是,這樣的編碼方式是最優(yōu)的設(shè)計(jì)嗎?如果我們讓不同的字符對(duì)應(yīng)不同長度的編碼,結(jié)果會(huì)怎樣呢?比如:
如此一來,給定的信息 “ABEFCDAED”,就可以編碼成二進(jìn)制的 “0 00 10 11 01 1 0 10 1”,編碼的總長度只有14。
哈夫曼編碼(Huffman Coding),同樣是由麻省理工學(xué)院的哈夫曼博所發(fā)明,這種編碼方式實(shí)現(xiàn)了兩個(gè)重要目標(biāo):
1.任何一個(gè)字符編碼,都不是其他字符編碼的前綴。
2.信息編碼的總長度最小。
哈夫曼編碼的生成過程是什么樣子呢?讓我們看看下面的例子:
假如一段信息里只有A,B,C,D,E,F這6個(gè)字符,他們出現(xiàn)的次數(shù)依次是2次,3次,7次,9次,18次,25次,如何設(shè)計(jì)對(duì)應(yīng)的編碼呢?
我們不妨把這6個(gè)字符當(dāng)做6個(gè)葉子結(jié)點(diǎn),把字符出現(xiàn)次數(shù)當(dāng)做結(jié)點(diǎn)的權(quán)重,以此來生成一顆哈夫曼樹:
這樣做的意義是什么呢?
哈夫曼樹的每一個(gè)結(jié)點(diǎn)包括左、右兩個(gè)分支,二進(jìn)制的每一位有0、1兩種狀態(tài),我們可以把這兩者對(duì)應(yīng)起來,結(jié)點(diǎn)的左分支當(dāng)做0,結(jié)點(diǎn)的右分支當(dāng)做1,會(huì)產(chǎn)生什么樣的結(jié)果?
這樣一來,從哈夫曼樹的根結(jié)點(diǎn)到每一個(gè)葉子結(jié)點(diǎn)的路徑,都可以等價(jià)為一段二進(jìn)制編碼:
上述過程借助哈夫曼樹所生成的二進(jìn)制編碼,就是哈夫曼編碼。
現(xiàn)在,我們面臨兩個(gè)關(guān)鍵的問題:
首先,這樣生成的編碼有沒有前綴問題帶來的歧義呢?答案是沒有歧義。
因?yàn)槊恳粋€(gè)字符對(duì)應(yīng)的都是哈夫曼樹的葉子結(jié)點(diǎn),從根結(jié)點(diǎn)到這些葉子結(jié)點(diǎn)的路徑并沒有包含關(guān)系,最終得到的二進(jìn)制編碼自然也不會(huì)是彼此的前綴。
其次,這樣生成的編碼能保證總長度最小嗎?答案是可以保證。
哈夫曼樹的重要特性,就是所有葉子結(jié)點(diǎn)的(權(quán)重 X 路徑長度)之和最小。
放在信息編碼的場(chǎng)景下,葉子結(jié)點(diǎn)的權(quán)重對(duì)應(yīng)字符出現(xiàn)的頻次,結(jié)點(diǎn)的路徑長度對(duì)應(yīng)字符的編碼長度。
所有字符的(頻次 X 編碼長度)之和最小,自然就說明總的編碼長度最小。
private?Node?root;private?Node[]?nodes;//構(gòu)建哈夫曼樹public?void?createHuffmanTree(int[]?weights)?{//優(yōu)先隊(duì)列,用于輔助構(gòu)建哈夫曼樹Queue?nodeQueue?=?new?PriorityQueue<>();????nodes?=?new?Node[weights.length];//構(gòu)建森林,初始化nodes數(shù)組for(int?i=0;?i?1)?{//從結(jié)點(diǎn)隊(duì)列選擇權(quán)值最小的兩個(gè)結(jié)點(diǎn)Node?left?=?nodeQueue.poll();Node?right?=?nodeQueue.poll();//創(chuàng)建新結(jié)點(diǎn)作為兩結(jié)點(diǎn)的父節(jié)點(diǎn)Node?parent?=?new?Node(left.weight?+?right.weight,?left,?right);????????nodeQueue.add(parent);}????root?=?nodeQueue.poll();}//輸入字符下表,輸出對(duì)應(yīng)的哈夫曼編碼public?String?convertHuffmanCode(int?index)?{return?nodes[index].code;}//用遞歸的方式,填充各個(gè)結(jié)點(diǎn)的二進(jìn)制編碼public?void?encode(Node?node,?String?code){if(node?==?null){return;}????node.code?=?code;????encode(node.lChild,?node.code+"0");????encode(node.rChild,?node.code+"1");}public?static?class?Node?implements?Comparable{int?weight;//結(jié)點(diǎn)對(duì)應(yīng)的二進(jìn)制編碼String?code;Node?lChild;Node?rChild;public?Node(int?weight)?{this.weight?=?weight;}public?Node(int?weight,?Node?lChild,?Node?rChild)?{this.weight?=?weight;this.lChild?=?lChild;this.rChild?=?rChild;}@Overridepublic?int?compareTo(Node?o)?{return?new?Integer(this.weight).compareTo(new?Integer(o.weight));}}public?static?void?main(String[]?args)?{char[]?chars?=?{'A','B','C','D','E','F'};int[]?weights?=?{2,3,7,9,18,25};HuffmanCode?huffmanCode?=?new?HuffmanCode();????huffmanCode.createHuffmanTree(weights);????huffmanCode.encode(huffmanCode.root,?"");for(int?i=0;?i這段代碼中,Node類增加了一個(gè)新字段code,用于記錄結(jié)點(diǎn)所對(duì)應(yīng)的二進(jìn)制編碼。
當(dāng)哈夫曼樹構(gòu)建之后,就可以通過遞歸的方式,從根結(jié)點(diǎn)向下,填充每一個(gè)結(jié)點(diǎn)的code值。
總結(jié)
以上是生活随笔為你收集整理的手机号段对应地区编码_漫画:“哈夫曼编码” 是什么鬼?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: range函数python3_Pytho
- 下一篇: mysql 8安装_mysql安装过程详