哈夫曼樹(shù)

轉(zhuǎn)自:http://blog.csdn.net/hikvision_java_gyh/article/details/8952596
哈夫曼樹(shù)又稱最優(yōu)二叉樹(shù)掰派,是一種帶權(quán)路徑長(zhǎng)度最短的二叉樹(shù)剂习。所謂樹(shù)的帶權(quán)路徑長(zhǎng)度,就是樹(shù)中所有的葉結(jié)點(diǎn)的權(quán)值乘上其到根結(jié)點(diǎn)的路徑長(zhǎng)度(若根結(jié)點(diǎn)為0層拆祈,葉結(jié)點(diǎn)到根結(jié)點(diǎn)的路徑長(zhǎng)度為葉結(jié)點(diǎn)的層數(shù))。樹(shù)的帶權(quán)路徑長(zhǎng)度記為WPL=(W1L1+W2L2+W3L3+...+ WnLn)长赞,N個(gè)權(quán)值Wi(i=1,2,...n)構(gòu)成一棵有N個(gè)葉結(jié)點(diǎn)的二叉樹(shù)声怔,相應(yīng)的葉結(jié)點(diǎn)的路徑長(zhǎng)度為L(zhǎng)i(i=1,2,...n)回懦。可以證明哈夫曼樹(shù)的WPL是最小的曾我》叟拢【例】給定4個(gè)葉子結(jié)點(diǎn)a,b抒巢,c和d贫贝,分別帶權(quán)7,5蛉谜,2和4稚晚。構(gòu)造如下圖所示的三棵二叉樹(shù)(還有許多棵),它們的帶權(quán)路徑長(zhǎng)度分別為: (a)WPL=72+52+22+42=36 (b)WPL=73+53+21+42=46 (c)WPL=71+52+23+43=35其中(c)樹(shù)的WPL最小型诚,可以驗(yàn)證客燕,它就是哈夫曼樹(shù)。

構(gòu)造哈夫曼樹(shù)的算法如下: 1)對(duì)給定的n個(gè)權(quán)值{W1,W2,W3,...,Wi,...,Wn}構(gòu)成n棵二叉樹(shù)的初始集合F={T1,T2,T3,...,Ti,..., Tn}狰贯,其中每棵二叉樹(shù)Ti中只有一個(gè)權(quán)值為Wi的根結(jié)點(diǎn)也搓,它的左右子樹(shù)均為空。 2)在F中選取兩棵根結(jié)點(diǎn)權(quán)值最小的樹(shù)作為新構(gòu)造的二叉樹(shù)的左右子樹(shù)涵紊,新二叉樹(shù)的根結(jié)點(diǎn)的權(quán)值為其左右子樹(shù)的根結(jié)點(diǎn)的權(quán)值之和傍妒。 3)從F中刪除這兩棵樹(shù),并把這棵新的二叉樹(shù)同樣以升序排列加入到集合F中摸柄。 4)重復(fù)2)和3)颤练,直到集合F中只有一棵二叉樹(shù)為止。 例如驱负,對(duì)于4個(gè)權(quán)值為1嗦玖、3、5跃脊、7的節(jié)點(diǎn)構(gòu)造一棵哈夫曼樹(shù)宇挫,其構(gòu)造過(guò)程如下圖所示:

可以計(jì)算得到該哈夫曼樹(shù)的路徑長(zhǎng)度WPL=(1+3)3+25+1*7=26。
哈夫曼編碼應(yīng)用 大數(shù)據(jù)量的圖像信息會(huì)給存儲(chǔ)器的存儲(chǔ)容量酪术,通信干線信道的帶寬捞稿,以及計(jì)算機(jī)的處理速度增加極大的壓力。單純靠增加存儲(chǔ)器容量拼缝,提高信道帶寬以及計(jì)算機(jī)的處理速度等方法來(lái)解決這個(gè)問(wèn)題是不現(xiàn)實(shí)的娱局,這時(shí)就要考慮壓縮。壓縮的關(guān)鍵在于編碼咧七,如果在對(duì)數(shù)據(jù)進(jìn)行編碼時(shí)衰齐,對(duì)于常見(jiàn)的數(shù)據(jù),編碼器輸出較短的碼字继阻;而對(duì)于少見(jiàn)的數(shù)據(jù)則用較長(zhǎng)的碼字表示耻涛,就能夠?qū)崿F(xiàn)壓縮废酷。【例】:假設(shè)一個(gè)文件中出現(xiàn)了8種符號(hào)S0抹缕,SQ澈蟆,S2,S3卓研,S4趴俘,S5,S6奏赘,S7寥闪,那么每種符號(hào)要編碼,至少需要3bit磨淌。假設(shè)編碼成 000疲憋,001, 010梁只,011缚柳,100,101搪锣,110喂击,111。那么符號(hào)序列S0S1S7S0S1S6S2S2S3S4S5S0S0S1編碼后變成 000001111000001110010010011100101000000001淤翔,共用了42bit。我們發(fā)現(xiàn)S0佩谷,S1旁壮,S2這3個(gè)符號(hào)出現(xiàn)的頻率比較大,其它符號(hào)出現(xiàn)的頻率比較小谐檀,我們采用這樣的編碼方案:S0到S7的碼遼分別01抡谐,11,101桐猬,0000麦撵,0001,0010溃肪,0011免胃, 100,那么上述符號(hào)序列變成011110001110011101101000000010010010111惫撰,共用了39bit羔沙。盡管有些碼字如 S3,S4厨钻,S5扼雏,S6變長(zhǎng)了(由3位變成4位)坚嗜,但使用頻繁的幾個(gè)碼字如S0,S1變短了诗充,所以實(shí)現(xiàn)了壓縮苍蔬。對(duì)于上述的編碼可能導(dǎo)致解碼出現(xiàn)非單值性:比如說(shuō),如果S0的碼字為01蝴蜓,S2的碼字為011碟绑,那么當(dāng)序列中出現(xiàn)011時(shí),你不知道是S0的碼字后面跟了個(gè)1励翼,還是完整的一個(gè)S2的碼字蜈敢。因此,編碼必須保證較短的編碼決不能是較長(zhǎng)編碼的前綴汽抚。符合這種要求的編碼稱之為前綴編碼抓狭。要構(gòu)造符合這樣的二進(jìn)制編碼體系,可以通過(guò)二叉樹(shù)來(lái)實(shí)現(xiàn)造烁。以下是哈夫曼樹(shù)的Java實(shí)現(xiàn):
[java] view plain copy

// 二叉樹(shù)節(jié)點(diǎn)
public class Node implements Comparable { private int value; private Node leftChild; private Node rightChild; public Node(int value) { this.value = value; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } public Node getLeftChild() { return leftChild; } public void setLeftChild(Node leftChild) { this.leftChild = leftChild; } public Node getRightChild() { return rightChild; } public void setRightChild(Node rightChild) { this.rightChild = rightChild; } public int compareTo(Object o) { Node that = (Node) o; double result = this.value - that.value; return result > 0 ? 1 : result == 0 ? 0 : -1; } }

  • 哈夫曼樹(shù)構(gòu)造類(lèi):
    public class HuffmanTreeBuilder { public static void main(String[] args) { List<Node> nodes = Arrays.asList( new Node(1), new Node(3), new Node(5), new Node(7) ); Node node = HuffmanTreeBuilder.build(nodes); PrintTree(node); }
    /**
  • 構(gòu)造哈夫曼樹(shù)
  • @param nodes 結(jié)點(diǎn)集合
  • @return 構(gòu)造出來(lái)的樹(shù)的根結(jié)點(diǎn)
    */

private static Node build(List<Node> nodes) {
nodes = new ArrayList<Node>(nodes);
sortList(nodes);
while (nodes.size() > 1) {
createAndReplace(nodes);
}
return nodes.get(0);
}

/**

  • 組合兩個(gè)權(quán)值最小結(jié)點(diǎn)否过,并在結(jié)點(diǎn)列表中用它們的父結(jié)點(diǎn)替換它們
  • @param nodes 結(jié)點(diǎn)集合
    */
    private static void createAndReplace(List<Node> nodes) {
    Node left = nodes.get(0);
    Node right = nodes.get(1);
    Node parent = new Node(left.getValue() + right.getValue());
    parent.setLeftChild(left);
    parent.setRightChild(right);
    nodes.remove(0);
    nodes.remove(0);
    nodes.add(parent);
    sortList(nodes);
    }

/**

  • 將結(jié)點(diǎn)集合由大到小排序
    */

private static void sortList(List<Node> nodes) {
Collections.sort(nodes);
}

`
/**

  • 打印樹(shù)結(jié)構(gòu),顯示的格式是node(left,right)
  • @param node
    */
    public static void PrintTree(Node node)
    {
    Node left = null;
    Node right = null;
    if(node!=null)
    {
    System.out.print(node.getValue());
    left = node.getLeftChild();
    right = node.getRightChild();
    System.out.println("("+(left!=null?left.getValue():" ") +","+ (right!= null?right.getValue():" ")+")");
    }
    if(left!=null)
    PrintTree(left);
    if(right!=null)
    PrintTree(right);
    }
    }
    `
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末惭蟋,一起剝皮案震驚了整個(gè)濱河市苗桂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌告组,老刑警劉巖煤伟,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異木缝,居然都是意外死亡便锨,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)我碟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)放案,“玉大人,你說(shuō)我怎么就攤上這事矫俺≈ㄑ常” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵厘托,是天一觀的道長(zhǎng)友雳。 經(jīng)常有香客問(wèn)我,道長(zhǎng)铅匹,這世上最難降的妖魔是什么沥阱? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮伊群,結(jié)果婚禮上考杉,老公的妹妹穿的比我還像新娘策精。我一直安慰自己,他們只是感情好崇棠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布咽袜。 她就那樣靜靜地躺著,像睡著了一般枕稀。 火紅的嫁衣襯著肌膚如雪询刹。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,541評(píng)論 1 305
  • 那天萎坷,我揣著相機(jī)與錄音凹联,去河邊找鬼。 笑死哆档,一個(gè)胖子當(dāng)著我的面吹牛蔽挠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播瓜浸,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼澳淑,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了插佛?” 一聲冷哼從身側(cè)響起杠巡,我...
    開(kāi)封第一講書(shū)人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎雇寇,沒(méi)想到半個(gè)月后氢拥,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡锨侯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年嫩海,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片识腿。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖造壮,靈堂內(nèi)的尸體忽然破棺而出渡讼,到底是詐尸還是另有隱情,我是刑警寧澤耳璧,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布成箫,位于F島的核電站,受9級(jí)特大地震影響旨枯,放射性物質(zhì)發(fā)生泄漏蹬昌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一攀隔、第九天 我趴在偏房一處隱蔽的房頂上張望皂贩。 院中可真熱鬧栖榨,春花似錦、人聲如沸明刷。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)辈末。三九已至愚争,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間挤聘,已是汗流浹背轰枝。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留组去,地道東北人鞍陨。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像添怔,于是被迫代替她去往敵國(guó)和親湾戳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容