zoukankan      html  css  js  c++  java
  • 哈夫曼树

    这一篇要总结的是树中的最后一种,即哈夫曼树,我想从以下几点对其进行总结:

    1,什么是哈夫曼树?

    2,如何构建哈夫曼树?

    3,哈夫曼编码?

    4,算法实现?

    一,什么是哈夫曼树

    什么是哈夫曼树呢?

    哈夫曼树是一种带权路径长度最短的二叉树,也称为最优二叉树。下面用一幅图来说明。

    ds48

    它们的带权路径长度分别为:

    图a: WPL=5*2+7*2+2*2+13*2=54

    图b: WPL=5*3+2*3+7*2+13*1=48

    可见,图b的带权路径长度较小,我们可以证明图b就是哈夫曼树(也称为最优二叉树)。

    二,如何构建哈夫曼树

    一般可以按下面步骤构建:

    1,将所有左,右子树都为空的作为根节点。

    2,在森林中选出两棵根节点的权值最小的树作为一棵新树的左,右子树,且置新树的附加根节点的权值为其左,右子树上根节点的权值之和。注意,左子树的权值应小于右子树的权值。

    3,从森林中删除这两棵树,同时把新树加入到森林中。

    4,重复2,3步骤,直到森林中只有一棵树为止,此树便是哈夫曼树。

    下面是构建哈夫曼树的图解过程:

    ds52

    三,哈夫曼编码

    利用哈夫曼树求得的用于通信的二进制编码称为哈夫曼编码。树中从根到每个叶子节点都有一条路径,对路径上的各分支约定指向左子树的分支表示”0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为各个叶子节点对应的字符编码,即是哈夫曼编码。

    就拿上图例子来说:

    A,B,C,D对应的哈夫曼编码分别为:111,10,110,0

    用图说明如下:

    ds50

    记住,设计电文总长最短的二进制前缀编码,就是以n个字符出现的频率作为权构造一棵哈夫曼树,由哈夫曼树求得的编码就是哈夫曼编码。

    四,算法实现

    1、节点类

    public class Note<T> implements Comparable<Note<T>> {
    
        private T data; //数据
        private int weight; //权值
        private Note<T> left; //左孩子
        private Note<T> right; //右孩子
        
        public Note(T data,int weight){
            this.data=data;
            this.weight=weight;
        }
        
        @Override
        public String toString(){
            return "data="+this.data+",weitht="+this.weight;
        }    
        
        public T getData() {
            return data;
        }
        public void setData(T data) {
            this.data = data;
        }
    
        public int getWeight() {
            return weight;
        }
        public void setWeight(int weight) {
            this.weight = weight;
        }
    
        public Note<T> getLeft() {
            return left;
        }
        public void setLeft(Note<T> left) {
            this.left = left;
        }
    
        public Note<T> getRight() {
            return right;
        }
        public void setRight(Note<T> right) {
            this.right = right;
        }
        
        
        @Override
        public int compareTo(Note<T> o) {
            if(o.weight>this.weight){
                return 1;
            }else if(o.weight<this.weight){
                return -1;
            }
            return 0;
        }
    
    }

    2、哈夫曼数操作类

    package test1;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Collections;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Queue;
    import java.util.Stack;
    
    public class HuffmanTree<T> {
        /**
         * 创建哈夫曼树
         * @param notes
         * @return
         */
        public static <T> Note<T> createTree(List<Note<T>> notes){
            while(notes.size()>1){
                Collections.sort(notes);
                Note<T> left=notes.get(notes.size()-1);
                Note<T> right=notes.get(notes.size()-2);
                Note<T> parent=new Note<T>(null,left.getWeight()+right.getWeight());
                parent.setLeft(left);
                parent.setRight(right);
                notes.remove(left);
                notes.remove(right);
                notes.add(parent);
            }
            return notes.get(0);
        }
        
        //前序遍历 非递归方式
        public static <T> List<Note<T>> breath(Note<T> root){
            List<Note<T>> list=new ArrayList<Note<T>>();
            Queue<Note<T>> queue=new LinkedList<>();
            queue.add(root);
            while(!queue.isEmpty()){
                Note<T> pNode=queue.poll();
                list.add(pNode);
                if(pNode.getLeft()!=null){
                    queue.add(pNode.getLeft());
                }
                if(pNode.getRight()!=null){
                    queue.add(pNode.getRight());
                }
            }
            return list;
        }
        /**
         * 中序遍历
         * @param root
         */
        public static <T> void midOrder(Note<T> root)
        {
            if (root != null)
            {
                midOrder(root.getLeft());
                System.out.println(root);
                midOrder(root.getRight());
            }
        }
        
        /**
         * 前序遍历
         * @param root
         */
         public static <T> void preOrder(Note<T> root){
             if (root != null)
                {
                     System.out.println(root);
                     preOrder(root.getLeft());
                     preOrder(root.getRight());
                }
           }
         /**
          * 后序遍历
          * @param root
          */
         public static<T> void posOrder(Note<T> root){
             if (root != null)
                {
                     posOrder(root.getLeft());
                     posOrder(root.getRight());
                     System.out.println(root);
                }
         }
         
         
         /**
          * 层级遍历
          * @param root
          */
         public static<T> void levelOrder(Note<T> root){
             if(root==null){
                 return;
             }
             int depth=depth(root);
             for(int i=1;i<=depth;i++){
                 levelOrder(root,i);
             }
         }
         
         
         private static<T> void levelOrder(Note<T> root,int level){
             if(root==null||level<1){
                 return;
             }
             if(level==1){
                 System.out.println(root);
                 return;
             }
             levelOrder(root.getLeft(),level-1);
             levelOrder(root.getRight(),level-1);
         }
         
         
         
         public static<T> int  depth(Note<T> root){
             if(root==null){
                 return 0;
             }
             int l=depth(root.getLeft());
             int r=depth(root.getRight());
             return l>r?l+1:r+1;
         }
         
    
    }

    3、测试类

    package test1;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class HuffmanTreeTest {
        public static void main(String[] args ){
            List<Note<String>> list=new ArrayList<Note<String>>();
            list.add(new Note<String>("b",5));
            list.add(new Note<String>("a",7));
            list.add(new Note<String>("d",2));
            list.add(new Note<String>("c",4));
            Note<String> root=HuffmanTree.createTree(list);
            //System.out.println(HuffmanTree.breath(root));
            HuffmanTree.midOrder(root);
            System.out.println("============================");
            HuffmanTree.preOrder(root);
            System.out.println("============================");
            HuffmanTree.posOrder(root);
            System.out.println("============================");
            HuffmanTree.levelOrder(root);
            
        }
    }

    4、测试结果

  • 相关阅读:
    几个开源项目实体层实现方式比较
    ASP.NET MVC+LINQ开发一个图书销售站点
    C#流程控制
    用Java实现多线程服务器程序
    C#修饰符
    C#中的转义字符
    自定义实体类简介
    JAVA学习笔记——多线程(并发)
    java 多线程 wait() 以及 notirfy() 简析
    OA系统权限管理设计
  • 原文地址:https://www.cnblogs.com/gengaixue/p/6913003.html
Copyright © 2011-2022 走看看