Java 數(shù)據(jù)結(jié)構(gòu) 哈夫曼編碼

介紹

上一篇文章我們講到了哈夫曼樹寂诱,相信看官們對其也有一定的了解了
http://www.reibang.com/p/bad3472aae5a(需先理解何為哈夫曼樹)

哈夫曼編碼(Huffman Coding),又稱霍夫曼編碼激蹲,是一種編碼方式腔呜,哈夫曼編碼是可變字長編碼(VLC)的一種叁温。Huffman于1952年提出一種編碼方法,該方法完全依據(jù)字符出現(xiàn)概率來構(gòu)造異字頭的平均長度最短的碼字核畴,有時稱之為最佳編碼膝但,一般就叫做Huffman編碼。

舉個例子

我們有 A, B, C, D 四個字符谤草,他們的出現(xiàn)頻率分別是1跟束,2莺奸,3,4(這也是他們的權(quán)值)
這個時候冀宴,我們根據(jù)哈夫曼樹的生成方式灭贷,將其構(gòu)建成一個哈夫曼樹


huffman1.png

之后,我們再給它的路徑添加上代碼(左分支0略贮,右分支1)
最后得出 A甚疟,B,C刨肃,D的哈夫曼編碼分別是100古拴,101,11真友,0


huffman2.png

java代碼實現(xiàn)

package tree;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Sheldon on 2019/4/11.
 * Project Name: alstudy.
 * Package Name: tree.
 */
// 數(shù)據(jù)類
class Data{
    public char key;
    public int value;
    public Data(char key, int value){
        this.key = key;
        this.value = value;
    }
}

// 結(jié)點結(jié)構(gòu)
class CodeNode{
    // 權(quán)值
    Data data;
    // 左結(jié)點
    CodeNode leftChild;
    // 右結(jié)點
    CodeNode rightChild;

    public CodeNode(Data data){
        this.data = data;
    }

    public CodeNode(Data data, CodeNode leftChild, CodeNode rightChild){
        this.leftChild = leftChild;
        this.rightChild = rightChild;
        this.data = data;
    }
}

public class HuffmanCode {

    /**
     * 創(chuàng)建哈弗曼樹
     * @param datas
     * @return
     */
    public static CodeNode createHuffmanTree(Data[] datas){
        // 將傳進(jìn)來的數(shù)組元素創(chuàng)建成結(jié)點
        List<CodeNode> nodes = new ArrayList<>();
        for (Data d: datas){
            nodes.add(new CodeNode(d));
        }
        // 循環(huán)處理以下操作
        while (nodes.size()>1){
            // 依據(jù)權(quán)值排序(選擇排序算法)
            CodeNode temp;
            for (int i=0; i<nodes.size(); i++){
                int k = i;
                for (int j=nodes.size()-1; j>i; j--){
                    if (nodes.get(j).data.value < nodes.get(k).data.value){
                        k = j;
                    }
                }
                temp = nodes.get(i);
                nodes.set(i, nodes.get(k));
                nodes.set(k, temp);
            }
            // 取出權(quán)值最小的兩個二叉樹
            CodeNode leftNode = nodes.get(0);
            CodeNode rightNode = nodes.get(1);
            // 創(chuàng)建新的二叉樹
            Data d = new Data('#', leftNode.data.value+rightNode.data.value);
            CodeNode parent = new CodeNode(d, leftNode, rightNode);
            // 移除取出的二叉樹
            nodes.remove(leftNode);
            nodes.remove(rightNode);
            // 放入原來的二叉樹集合中
            nodes.add(parent);
        }
        return nodes.get(0);
    }

    static StringBuilder sb = new StringBuilder();          // 存儲編碼字符
    static Map<String, String> huffcodes = new HashMap<>();  // 存儲編碼表

    /**
     * 創(chuàng)建哈夫曼編碼編碼表
     * @param codeNode
     * @return
     */
    public static Map<String, Integer> createCode(CodeNode codeNode){
        if (codeNode==null){
            return null;
        }
        getCode(codeNode.leftChild, "0", sb);
        getCode(codeNode.rightChild, "1", sb);
        return null;
    }

    public static void getCode(CodeNode codeNode, String code, StringBuilder sb){
        StringBuilder sb2 = new StringBuilder(sb);
        sb2.append(code);
        if (codeNode.data==null||codeNode.data.key=='#'){
            getCode(codeNode.leftChild,"0",sb2);
            getCode(codeNode.rightChild,"1",sb2);
        }else {
            huffcodes.put(String.valueOf(codeNode.data.key),sb2.toString());
        }
    }

    public static void main(String[] args) {
        String plaintext = "ABCBCDCDDD";
        char[] ch = plaintext.toCharArray();
        Map<String,Integer> textMap = new HashMap<>();
        // 統(tǒng)計字符出現(xiàn)次數(shù)
        for (char c : ch) {
            String cTo = String.valueOf(c);
            if (!textMap.containsKey(cTo)) {
                textMap.put(cTo, 1);
            } else {
                textMap.put(cTo, textMap.get(cTo) + 1);
            }
        }
        System.out.println(textMap.entrySet());
        // 創(chuàng)建結(jié)點數(shù)組
        Data[] datas = new Data[textMap.size()];
        int i = 0;
        // 結(jié)點數(shù)組的元素對象創(chuàng)建
        for (Map.Entry<String, Integer> entry: textMap.entrySet()) {
            datas[i] = new Data(entry.getKey().charAt(0),entry.getValue());
            i++;
        }
        // 創(chuàng)建哈夫曼樹
        CodeNode root = HuffmanCode.createHuffmanTree(datas);
        // 創(chuàng)建哈夫曼編碼表
        HuffmanCode.createCode(root);
        // 輸出哈夫曼樹
        System.out.println(HuffmanCode.huffcodes);
        StringBuilder textSb = new StringBuilder();
        // 加密文本信息
        for (char c: ch) {
            textSb.append(HuffmanCode.huffcodes.get(String.valueOf(c)));
        }
        // 輸出加密前的信息
        System.out.println("加密前:"+plaintext);
        // 輸出加密后的信息
        System.out.println("加密后:"+textSb);
    }
}

結(jié)果

結(jié)果.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末黄痪,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子盔然,更是在濱河造成了極大的恐慌桅打,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件愈案,死亡現(xiàn)場離奇詭異挺尾,居然都是意外死亡,警方通過查閱死者的電腦和手機站绪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門遭铺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人恢准,你說我怎么就攤上這事魂挂。” “怎么了馁筐?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵涂召,是天一觀的道長。 經(jīng)常有香客問我敏沉,道長果正,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任盟迟,我火速辦了婚禮秋泳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘攒菠。我一直安慰自己轮锥,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布要尔。 她就那樣靜靜地躺著舍杜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赵辕。 梳的紋絲不亂的頭發(fā)上既绩,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機與錄音还惠,去河邊找鬼饲握。 笑死,一個胖子當(dāng)著我的面吹牛蚕键,可吹牛的內(nèi)容都是我干的救欧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼锣光,長吁一口氣:“原來是場噩夢啊……” “哼笆怠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起誊爹,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蹬刷,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后频丘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體办成,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年搂漠,在試婚紗的時候發(fā)現(xiàn)自己被綠了迂卢。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡桐汤,死狀恐怖而克,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情惊科,我是刑警寧澤拍摇,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站馆截,受9級特大地震影響充活,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蜡娶,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一混卵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧窖张,春花似錦幕随、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽辕录。三九已至,卻和暖如春梢卸,著一層夾襖步出監(jiān)牢的瞬間走诞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工蛤高, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蚣旱,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓戴陡,卻偏偏與公主長得像塞绿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子恤批,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,933評論 2 355

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