哈夫曼编码记录

Posted gao-kuanrang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了哈夫曼编码记录相关的知识,希望对你有一定的参考价值。

哈夫曼编码与哈夫曼树

  • 哈夫曼编码:又称霍夫曼编码,是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫做Huffman编码(有时也称为霍夫曼编码)。
  • 哈夫曼树:给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。

实验内容

哈夫曼编码测试
设有字符集: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)把实验结果截图上传到云班课

重点代码

构造哈夫曼树:

   public static HuffmanNode createTree(List<HuffmanNode> nodes) {

    // 只要nodes数组中还有2个以上的节点
    while (nodes.size() > 1)
    {
        quickSort(nodes);

        //获取权值最小的两个节点
        HuffmanNode left = nodes.get(nodes.size()-1);
        left.setCodeNumber(0+"");
        HuffmanNode right = nodes.get(nodes.size()-2);
        right.setCodeNumber(1+"");

        //生成新节点,新节点的权值为两个子节点的权值之和
        HuffmanNode parent = new HuffmanNode(null, left.weight + right.weight);

        //让新节点作为两个权值最小节点的父节点
        parent.leftChild = left;
        parent.rightChild = right;

        //删除权值最小的两个节点
        nodes.remove(nodes.size()-1);
        nodes.remove(nodes.size()-1);

        //将新节点加入到集合中
        nodes.add(parent);
    }
    return nodes.get(0);
}

/**
 * 将指定集合中的i和j索引处的元素交换
 *
 * @param nodes
 * @param i
 * @param j
 */
private static void swap(List<HuffmanNode> nodes, int i, int j) {

    HuffmanNode tmp;
    tmp = nodes.get(i);

    nodes.set(i, nodes.get(j));
    nodes.set(j, tmp);

}

/**
 * 实现快速排序算法,用于对节点进行排序
 * @param nodes
 * @param start
 * @param end
 */
private static void subSort(List<HuffmanNode> nodes, int start, int end)
{

    if (start < end)
    {
        // 以第一个元素作为分界值
        HuffmanNode base = nodes.get(start);
        // i从左边搜索,搜索大于分界值的元素的索引
        int i = start;
        // j从右边开始搜索,搜索小于分界值的元素的索引
        int j = end + 1;
        while (true)
        {
            // 找到大于分界值的元素的索引,或者i已经到了end处
            while (i < end && nodes.get(++i).weight >= base.weight);
            // 找到小于分界值的元素的索引,或者j已经到了start处
            while (j > start && nodes.get(--j).weight <= base.weight);
            if (i < j)
            {
                swap(nodes, i, j);
            }
            else
                break;
        }

        swap(nodes, start, j);

        //递归左边子序列
        subSort(nodes, start, j - 1);
        //递归右边子序列
        subSort(nodes, j + 1, end);
    }
}

public static void quickSort(List<HuffmanNode> nodes)
{
    subSort(nodes, 0, nodes.size()-1);
}

//层序遍历
public static List<HuffmanNode> levelTraversal(HuffmanNode root)
{
    Queue<HuffmanNode> queue = new ArrayDeque<HuffmanNode>();
    List<HuffmanNode> list = new ArrayList<HuffmanNode>();

    if(root!=null)
    {
        //将根元素加入“队列”
        queue.offer(root);
        root.leftChild.setCodeNumber(root.getCodeNumber()+"0");
        root.rightChild.setCodeNumber(root.getCodeNumber()+"1");
    }

    while(!queue.isEmpty())
    {
        //将该队列的“队尾”元素加入到list中
        list.add(queue.peek());

        HuffmanNode tree = queue.poll();
        //如果左子节点不为null,将它加入到队列
        if(tree.leftChild != null)
        {
            queue.offer(tree.leftChild);
            tree.leftChild.setCodeNumber(tree.getCodeNumber()+"0");
        }

        //如果右子节点不为null,将它加入到队列
        if(tree.rightChild != null)
        {
            queue.offer(tree.rightChild);
            tree.rightChild.setCodeNumber(tree.getCodeNumber()+"1");
        }
    }

    return list;

}

计算字母出现次数:

   //层序遍历显示构建的哈弗曼树
    char[] chars = new char[a];
    int[] times = new int[a];
    Iterator<Character> pl2 = counter.keySet().iterator();

    for (int i=0;i<=a;i++ )
    {
        if (pl2.hasNext())
        {
            chars[i] = pl2.next();
            times[i] = counter.get(chars[i]);
        }

    }
    List<HuffmanNode> list = new ArrayList<HuffmanNode>();

    for(int i = 0;i<a;i++)
    {
        System.out.print(chars[i]+"出现次数为:"+times[i]+"   
");
        list.add(new HuffmanNode(chars[i]+"",times[i]));
    }

读取文件:

 File file = new File("c:\\huffman\\read.txt");

    if (!file.exists()) {
        throw new Exception("文件不存在");
    }

    BufferedReader fin = new BufferedReader(new FileReader(file));
    String line;


    Map<Character, Integer> counter = new HashMap<Character, Integer>();

    int total=0;


    while ((line = fin.readLine()) != null)
    {
        int len = line.length();
        for (int i = 0; i < len; i++)
        {
            char c = line.charAt(i);
            if (( (c >= 'a' && c <= 'z'&& c == ' ')))
            {
                continue;
            }
            if (counter.containsKey(c))
            {
                counter.put(c, counter.get(c) + 1);
            }
            else
            {
                counter.put(c, 1);
            }
        }
    }

    fin.close();
    

实验结果截图

技术图片

技术图片

以上是关于哈夫曼编码记录的主要内容,如果未能解决你的问题,请参考以下文章

哈夫曼编码C语言实现

哈夫曼编码压缩与解压思路分析与Java代码实现

怎么样用c语言程序编码哈夫曼树?

贪心算法应用-哈夫曼编码

百度看到您的 请问 那个哈夫曼树和哈夫曼编码。。。跪谢!

数据结构树与树的表示二叉树存储结构及其遍历二叉搜索树平衡二叉树堆哈夫曼树与哈夫曼编码集合及其运算