求赫夫曼編碼的算法

求赫夫曼編碼的算法

參考清華大學出版社出版的《數據結構(c語言版)》一書,在java下實現

//數據結構
class HuffmanNode{
    public int weight;//權重
    public int parent,lchild,rchild;//父節點、孩子節點在數組中的下標位置

    public HuffmanNode(int weight,int parent,int lchild,int rchild){
        this.weight = weight;
        this.parent = parent;
        this.lchild = lchild;
        this.rchild = rchild;
    }
}

    /**
     * @param str_weight_arr 存放字符權值的數組
     * @param n 字符的數量
     * @return 計算好的赫夫曼編碼
     * */
    public String huffmanCoding(int[] str_weight_arr,int n){

        if(n<1 || str_weight_arr.length <n)
            return null;
        //要構造的赫夫曼樹的結點數量爲葉子結點數量的二倍減1
        int node_num = n*2-1;
        //創建赫夫曼樹結點數組,數組大小爲node_num+1,我們從下標1開始使用
        HuffmanNode[] huffmanTree = new HuffmanNode[node_num+1];
        //將str_weight_arr中的值放入前n個結點中,這前n個元素就是赫夫曼樹的葉子結點
        //而剩下的元素則是屬於非葉子結點的位置,也就是我們下面需要動態添加的
        for(int i=1;i<=n;i++)
            huffmanTree[i] = new HuffmanNode(str_weight_arr[i], 0, 0, 0);
        //初始化剩下的元素
        for(int i=n+1;i<=node_num;i++)
            huffmanTree[i] = new HuffmanNode(0, 0, 0, 0);

        //建立赫夫曼樹,從下標爲n+1的元素開始,逐個建立子樹。i的孩子結點是從1到i-1之間權重最小的
        //兩個結點,當遍歷結束後,下標爲node_num的元素就是赫夫曼樹的根結點
        for(int i=n+1;i<=node_num;i++){
            //在huffmanTree中下標爲1到i-1之間尋找權重最小並且沒有父節點的兩個元素的下標
            int[] child_arr = selectMinTwo(huffmanTree,1,i-1);
            //判斷下child_arr非空
            if(child_arr == null)
                return null;

            //構造新的子樹,根結點的下標爲i,左右子樹的位置爲child_arr[0],child_arr[1]
            huffmanTree[i].lchild = child_arr[0];
            huffmanTree[i].rchild = child_arr[1];
            huffmanTree[i].weight = huffmanTree[child_arr[0]].weight
                    +huffmanTree[child_arr[1]].weight;
            huffmanTree[child_arr[0]].parent = i;
            huffmanTree[child_arr[1]].parent = i;
        }//end for

        //此時,從下標爲n+1到node_num的位置上,這些非葉子結點的權重在逐漸增大。

        //接下來要生成赫夫曼編碼了
        String[] huffmanCode = new String[n+1];
        //code_temp數組中的全部元素就是一個字母的赫夫曼編碼
        char[] code_temp = new char[n];
        //將huffmanCode塞滿,下標從1開始
        for(int i=1;i<=n;i++){
            int start = n-1;
            //我們要求的是給定的字符串的赫夫曼編碼,方法傳入的是和字符串中字符一一對應的權重數組
            //所以,要按照順序,從每個結點開始,向上找,直到找到跟結點爲止,用0和1記錄期間的路徑
            //從葉子到根逆向求編碼 f==0時說明已經找到了根結點
            for(int c=1,f=huffmanTree[i].parent;f!=0;c=f,f=huffmanTree[f].parent){
                //c位置的結點不是f位置結點的左子樹就是f位置結點的右子樹,沒得跑
                if(huffmanTree[f].lchild == c)
                    code_temp[--start] = '0';
                else
                    code_temp[--start] = '1';
            }
            //第i個字符的赫夫曼碼找出來了,將code_temp數組的第start位置到最後的字符截斷
            //賦值給huffmanCode[i]
            huffmanCode[i] = String.copyValueOf(code_temp, start, code_temp.length-start);
        }

        String result = "";
        for(String s:huffmanCode)
            result+=s;

        return result;

    }

    private int[] selectMinTwo(HuffmanNode[] huffmanTree,int begin,int end){
        if(begin<1 || end >huffmanTree.length)
            return null;

        int max1 = begin;
        int max2 = begin;
        int max_weight = huffmanTree[begin].weight;
        //尋找最小的權重的元素所在下標
        for(int i=begin;i<=end;i++){
            if(huffmanTree[i].weight<max_weight && huffmanTree[i].parent == 0)
                max1 = i;
        }
        //尋找第二小的權重的元素所在下標
        for(int i=begin;i<=end;i++){
            if(huffmanTree[i].weight<max_weight && huffmanTree[i].parent == 0
                    && max1 != max2)
                max2 = i;
        }

        return new int[]{max1,max2};

    }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章