哈夫曼編碼測試

1.哈夫曼樹介紹

在計算機數據處理中,霍夫曼編碼使用變長編碼表對源符號(如文件中的一個字母)進行編碼,其中變長編碼表是經過一種評估來源符號出現機率的方法獲得的,出現機率高的字母使用較短的編碼,反之出現機率低的則使用較長的編碼,這便使編碼以後的字符串的平均長度、指望值下降,從而達到無損壓縮數據的目的。java

例如,在英文中,e的出現機率最高,而z的出現機率則最低。當利用霍夫曼編碼對一篇英文進行壓縮時,e極有可能用一個比特來表示,而z則可能花去25個比特(不是26)。用普通的表示方法時,每一個英文字母均佔用一個字節(byte),即8個比特。兩者相比,e使用了通常編碼的1/8的長度,z則使用了3倍多。假若咱們能實現對於英文中各個字母出現機率的較準確的估算,就能夠大幅度提升無損壓縮的比例。node

霍夫曼樹又稱最優二叉樹,是一種帶權路徑長度最短的二叉樹。所謂樹的帶權路徑長度,就是樹中全部的葉結點的權值乘上其到根結點的路徑長度(若根結點爲0層,葉結點到根結點的路徑長度爲葉結點的層數)。樹的路徑長度是從樹根到每一結點的路徑長度之和,記爲WPL=(W1L1+W2L2+W3L3+...+WnLn),N個權值Wi(i=1,2,...n)構成一棵有N個葉結點的二叉樹,相應的葉結點的路徑長度爲Li(i=1,2,...n)。能夠證實霍夫曼樹的WPL是最小的。數據結構

演算過程
進行霍夫曼編碼前,咱們先建立一個霍夫曼樹。app


⒈將每一個英文字母依照出現頻率由小排到大,最小在左。ui

⒉每一個字母都表明一個終端節點(葉節點),比較F.O.R.G.E.T五個字母中每一個字母的出現頻率,將最小的兩個字母頻率相加合成一個新的節點。如Fig.2所示,發現F與O的頻率最小,故相加2+3=5。this

⒊比較5.R.G.E.T,發現R與G的頻率最小,故相加4+4=8。編碼

⒋比較5.8.E.T,發現5與E的頻率最小,故相加5+5=10。加密

⒌比較8.10.T,發現8與T的頻率最小,故相加8+7=15。.net

⒍最後剩10.15,沒有能夠比較的對象,相加10+15=25。設計

進行編碼

1.給霍夫曼樹的全部左鏈結'0'與
霍夫曼樹
霍夫曼樹
右鏈結'1'。

2.從樹根至樹葉依序記錄全部字母的編碼

2.實驗內容

設有字符集:S={a,b,c,d,e,f,g,h,i,j,k,l,m,n.o.p.q,r,s,t,u,v,w,x,y,z}。
給定一個包含26個英文字母的文件,統計每一個字符出現的機率,根據計算的機率構造一顆哈夫曼樹。
並完成對英文文件的編碼和解碼。
要求:
(1)準備一個包含26個英文字母的英文文件(能夠不包含標點符號等),統計各個字符的機率
(2)構造哈夫曼樹
(3)對英文文件進行編碼,輸出一個編碼後的文件
(4)對編碼文件進行解碼,輸出一個解碼後的文件
(5)撰寫博客記錄實驗的設計和實現過程,並將源代碼傳到碼雲
(6)把實驗結果截圖上傳到雲班課
滿分:6分。
酌情打分。

3. 實驗過程及結果

HuffmanNode類 實現哈夫曼樹的結點

public class HuffmanNode   {
    private int weight;//權值
    private int parent;
    private int leftChild;
    private int rightChild;

    public HuffmanNode(int weight,int parent,int leftChild,int rightChild){
        this.weight=weight;
        this.parent=parent;
        this.leftChild=leftChild;
        this.rightChild=rightChild;
    }

    void setWeight(int weight){
        this.weight=weight;
    }

    void setParent(int parent){
        this.parent=parent;
    }

    void setLeftChild(int leftChild){
        this.leftChild=leftChild;
    }

    void setRightChild(int rightChild){
        this.rightChild=rightChild;
    }

    int getWeight(){
        return weight;
    }

    int getParent(){
        return parent;
    }

    int getLeftChild(){
        return leftChild;
    }

    int getRightChild(){
        return rightChild;
    }
}

HuffmanCode 類 記錄所用的字符及對應的編碼

public class HuffmanCode {
    private String character;
    private String code;
    HuffmanCode(String character,String code){
        this.character=character;
        this.code=code;
    }
    HuffmanCode(String code){
        this.code= code;
    }

    void setCharacter(String character){
        this.character=character;
    }

    void setCode(String code){
        this.code=code;
    }

    String getCharacter(){
        return character;
    }

    String getCode(){
        return code;
    }
}

HuffmanTree類,實現哈夫曼樹以及每一個符號得到對應的前綴碼

public class HuffmanTree {
    //初始化一個huffuman樹
    public static void initHuffmanTree(HuffmanNode[] huffmanTree,int m){
        for(int i=0;i<m;i++){
            huffmanTree[i] = new HuffmanNode(0,-1,-1,-1);
        }
    }

    //初始化一個huffmanCode
    public static void initHuffmanCode(HuffmanCode[] huffmanCode,int n){
        for(int i=0;i<n;i++){
            huffmanCode[i]=new HuffmanCode("","");
        }
    }

    //獲取huffmanCode的符號
    public static void getHuffmanCode(HuffmanCode[] huffmanCode , int n,char[] chars){
        for(int i=0;i<n;i++){
            String temp = ""+chars[i];
            huffmanCode[i] = new HuffmanCode(temp,"");
        }
    }

    //獲取huffman樹節點頻數
    public static void getHuffmanWeight(HuffmanNode[] huffmanTree , int n,int[] ints){
        for(int i=0;i<n;i++){
            int temp = ints[i];
            huffmanTree[i] = new HuffmanNode(temp,-1,-1,-1);
        }
    }

    //從n個結點中選取最小的兩個結點
    public static int[] selectMin(HuffmanNode[] huffmanTree ,int n)
    {
        int min[] = new int[2];
        class TempNode
        {
            int newWeight;//存儲權
            int place;//存儲該結點所在的位置

            TempNode(int newWeight,int place){
                this.newWeight=newWeight;
                this.place=place;
            }

            void setNewWeight(int newWeight){
                this.newWeight=newWeight;
            }

            void setPlace(int place){
                this.place=place;
            }

            int getNewWeight(){
                return newWeight;
            }

            int getPlace(){
                return place;
            }
        }

        TempNode[] tempTree=new TempNode[n];

        //將huffmanTree中沒有雙親的結點存儲到tempTree中
        int i=0,j=0;
        for(i=0;i<n;i++)
        {
            if(huffmanTree[i].getParent()==-1&& huffmanTree[i].getWeight()!=0)
            {
                tempTree[j]= new TempNode(huffmanTree[i].getWeight(),i);
                j++;
            }
        }

        int m1,m2;
        m1=m2=0;
        for(i=0;i<j;i++)
        {
            if(tempTree[i].getNewWeight()<tempTree[m1].getNewWeight())//此處不讓取到相等,是由於結點中有相同權值的時候,m1取最前的
                m1=i;
        }
        for(i=0;i<j;i++)
        {
            if(m1==m2)
                m2++;//當m1在第一個位置的時候,m2向後移一位
            if(tempTree[i].getNewWeight()<=tempTree[m2].getNewWeight()&& i!=m1)//此處取到相等,是讓在結點中有相同的權值的時候,

                //m2取最後的那個。
                m2=i;
        }

        min[0]=tempTree[m1].getPlace();
        min[1]=tempTree[m2].getPlace();
        return min;
    }

    //建立huffmanTree
    public static void createHaffmanTree(HuffmanNode[] huffmanTree,int n){
        if(n<=1)
            System.out.println("Parameter Error!");
        int m = 2*n-1;
        //initHuffmanTree(huffmanTree,m);

        for(int i=n;i<m;i++)
        {
            int[] min=selectMin(huffmanTree,i);
            int min1=min[0];
            int min2=min[1];
            huffmanTree[min1].setParent(i);
            huffmanTree[min2].setParent(i);
            huffmanTree[i].setLeftChild(min1);
            huffmanTree[i].setRightChild(min2);
            huffmanTree[i].setWeight(huffmanTree[min1].getWeight()+ huffmanTree[min2].getWeight());
        }
    }

    //建立huffmanCode
    public static void createHaffmanCode(HuffmanNode[] huffmanTree,HuffmanCode[] huffmanCode,int n){
        char[] code = new char[26];
        int start;
        int c;
        int parent;
        int temp;

        code[n-1]='0';
        for(int i=0;i<n;i++)
        {
            StringBuffer stringBuffer = new StringBuffer();
            start=n-1;
            c=i;
            while( (parent=huffmanTree[c].getParent()) >=0 )
            {
                start--;
                code[start]=((huffmanTree[parent].getLeftChild()==c)?'0':'1');
                c=parent;

            }
            for(;start<n-1;start++){
                stringBuffer.append(code[start]);
            }
            huffmanCode[i].setCode(stringBuffer.toString());
        }
    }

HuffmanTest類 讀取相應的文件並作出加密解密操做

import java.io.*;

import static week15.HuffmanTree.*;

public class HuffmanTest {
    private char[] chars = new char[]{'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s'
            ,'t','u','v','w','x','y','z'};
    private  int[] number = new int[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

    public String txtString(File file){
        StringBuilder result = new StringBuilder();
        try{
            BufferedReader br = new BufferedReader(new FileReader(file));//構造一個BufferedReader類來讀取文件
            String s = null;
            while((s = br.readLine())!=null){//使用readLine方法,一次讀一行
                result.append(System.lineSeparator()+s);
                num(s);
            }
            br.close();
        }catch(Exception e){
            e.printStackTrace();
        }
        return result.toString();
    }

    public void num(String string){
        for(int i = 0;i<26;i++){
            int temp = 0;
            for(int j = 0;j<string.length();j++){
                if(string.charAt(j) == chars[i])
                    temp++;
            }
            number[i] += temp;
        }
    }

    public int[] getNumber(){
        return number;
    }

    public char[] getChars(){
        return chars;
    }

    public static void main(String[] args){
        File file = new File("D:\\","inputhuffman.txt");
        HuffmanTest huffmanTest= new HuffmanTest();
        String temp = huffmanTest.txtString(file);
        int[] num = huffmanTest.getNumber();

        char[] chars = huffmanTest.getChars();

        int n;
        int m;
        n = 26;
        m=2*n-1;
        HuffmanNode[] huffmanTree = new HuffmanNode[m];
        HuffmanCode[] huffmanCode = new HuffmanCode[n];

        //初始化huffmanTree,huffmanCode
        initHuffmanTree(huffmanTree,m);
        initHuffmanCode(huffmanCode,n);

        //獲取huffmanCode的符號
            getHuffmanCode(huffmanCode,n,chars);
        //獲取huffmanTree的頻數
            getHuffmanWeight(huffmanTree,n,num);

        //建立huffmanTree
        createHaffmanTree(huffmanTree,n);
        //建立huffmanCode
        createHaffmanCode(huffmanTree,huffmanCode,n);

        //輸出huffmanCode編碼
        ouputHaffmanCode(huffmanCode,n);

        String result = "";
        for(int i = 0;i<temp.length();i++){
            for(int j = 0;j<huffmanCode.length;j++){
                if(temp.charAt(i) == huffmanCode[j].getCharacter().charAt(0))
                    result +=huffmanCode[j].getCode();
            }
        }
        System.out.println("加密");
        System.out.println(result);
        System.out.println("解密");
}

3. 實驗過程當中遇到的問題和解決過程

問題1:只輸出了兩個數的編碼

問題1解決方案:
錯誤地將26個字符數刪成兩個 因而其餘地方輸入多少個也沒用

改正以後就沒問題了

其餘(感悟、思考等)

參考資料

相關文章
相關標籤/搜索