求赫夫曼编码的算法

求赫夫曼编码的算法

参考清华大学出版社出版的《数据结构(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};

    }

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值