哈夫曼编码-二叉树应用

其中包含两个案列,一个是特定的编码,还有一种是键盘输入自动计算权值以及解码。案例一分别使用了数组和链式栈实现哈夫曼树的编码同时可以计算压缩率,案例二使用先序遍历进行编码计算总码长


具体代码如下

主类

public class Testmian {//测试类
   public static void main(String[] args) {//传入固定字符和频率
     char[] ch={'a','b','c','d','e','f','g','h'};
     double[] weight={0.03,0.06,0.09,0.12,0.15,0.18,0.21,0.16};
     HFMTool hfm1=new HFMTool(ch,weight);
     //设置需要编码的字符输入字符串进行解码
     HFMTool hfm2=new HFMTool();
     hfm2.create();//创建哈夫曼树并输出结构和所有的字符编码
     String op="";
     do{
          System.out.println("请输入一个报文进行编码:");
          Scanner sc = new Scanner(System.in);
          String codes=sc.nextLine();
          String decodes=hfm2.decodes(codes);
          if(decodes.length()==0){
             System.out.println("解  码  出  错   !");
          }else{
            System.out.println("对应报文为:"+decodes);
          }
          System.out.println("按X键退出按其他任意键继续执行:");
          op=sc.nextLine();
       }while(!op.toLowerCase().equals("x"));
   }
}


三中数据结构

哈弗曼树节点的设计

public class HFMTreeNode {//哈弗曼树节点的设计
   double weight;
   int parent,lchild,rchild;
   String code,name;
   HFMTreeNode(){
       weight=0;
       parent=lchild=rchild=-1;
   } 
}

哈夫曼编码节点的设计

public class HFMCodeNode {//哈夫曼编码节点的设计
  int[] bit;//存储叶节点的编码0或1
  int start;//标记bit数组为真正编码存储开始的位置。
  HFMCodeNode(int n){//n为哈夫曼树的叶节点数目,节点数为n的哈夫曼树的长度最多为n-1个
     bit=new int[n];
     start=n-1;
  }
}

链式栈的实现用于哈夫曼编码

public interface IStack {//栈接口 用于实现链式栈
 E push(E item); //入栈
 E pop(); //出栈
 E peek(); //取栈顶元素
 int size(); //返回栈中元素的个数
 boolean empty(); //判断栈是否为空
}

public class StackNode {//定义对数据设置获取等基本操作,简化对对象的操作步骤,链表的结构所以从链头加入
   private E data; // 数据域
   private StackNode next; // 引用域
   //构造函数
   public StackNode(){}
     public StackNode(E data) {
     this.data = data;
   }
   public StackNode(E data, StackNode next) {
       super();
       this.data = data;
       this.next = next;
   }
   //数据域get属性
   public E getData() {
     return data;
   }
  //数据域set属性
  public void setData(E data) {
     this.data = data;
  }
  //引用域get属性
  public StackNode getNext() {
    return next;
  }
  //引用域get属性
  public void setNext(StackNode next) {
    this.next = next;
  }
}

public class LinkStack implements IStack {
  private StackNode top; // 栈顶指示器
  private int size; // 栈中结点的个数
  // 初始化链栈
  public LinkStack() {
    top = null;
    size = 0;
  }
  // 入栈操作
  public E push(E item) {
    StackNode newnode = new StackNode(item);
    if (!empty()) 
    newnode.setNext(top);
    top = newnode;
    ++size;
    return item;
  }
  // 出栈操作
  public E pop() {
    E item=null;
    if (!empty()){
        item = top.getData();
        top = top.getNext();
        size--;
    }    
    return item;
  }
  // 获取栈顶数据元素
  public E peek() {
    E item=null;
    if (!empty()){
       item=top.getData();
    }
    return item;
  }
  // 求栈的长度
  public int size() {
     return size;
  }
  // 判断顺序栈是否为空
  public boolean empty() {
     if ((top == null) && (size == 0)){
       return true;
     }else{
       return false;
     }
  }
}

主方法类


public class HFMTool {//计算哈夫曼树实现哈弗曼编码
   private int leaf;//树的结点的数量
   private HFMTreeNode[] data;//数据存储结构
   private int len;//报文大小 
   //构造方法
   public HFMTool(){}
   public HFMTool(String str){//读入字符串 
   }
   //传入固定字符和频率
   public HFMTool(char[] ch,double[] weight){  
      createHFMTree(ch,weight);
   }
   //计算哈夫曼树
   public static void createHFMTree(char[] cn,double[] weight){
   int n=cn.length;
   //创建哈弗曼树数组
   HFMTreeNode[] hfmtree=new HFMTreeNode[2*n-1];
   //初始化哈弗曼树数组
   for(int i=0;i<2*n-1;i++)
     hfmtree[i]=new HFMTreeNode();
   //给哈弗曼树节点权值
   for(int i=0;i();
 int c=i;//当前结点 
 int p=hfmtree[i].parent;//该结点的父结点
 int o=0;//统计编码数
 int one=0,two=0,three=0;//用于标记编码的最高三位 当不足三位时补0
 while(p!=-1){
   if(hfmtree[p].lchild==c){
     stack.push(a);o++;
     if(o==1){
        one=1;
     }else if(o==2){
        two=1;
     }else if(o==3){
        three=1;
     }
   }else if(hfmtree[p].rchild==c){
     stack.push(b);o++;
   }
   c=p;//父结点为当前结点
   p=hfmtree[c].parent; 
  } 
  m[i]=o;
  pnthfmcode2(stack,aa[i],o);
}
 //计算用三位二进行数进行的等长编码平均长度为3的平均码长 
 for(int g=0;g0)
     cnt++;
    }
    for(int i=0;i0)  
        c[i]=c[i]/str.length();
        }
    this.leaf=cnt;
     
    data = new HFMTreeNode[this.leaf*2-1];
    for(int i=0;i<2*leaf-1;i++)
     data[i]=new HFMTreeNode();
     
    cnt=0;
    char[] aa = new char[this.leaf];int o=0;//统计出现过的字符
    for(int i=0;i<26;i++){//用字符创建叶子结点
      if(c[i]>0){
      data[cnt].name=(char)(i+'a')+"";
      data[cnt++].weight=c[i];
      aa[o++]=(char)(i+'a');
      }
    }
    double x1,x2;//记录每次选择的两个最小值,x1 q=new LinkedList();//设置一个队列保存层序遍历的结点
    q.add(data[root]);//根结点入队
    int i=0;
    String str="";
    while(!q.isEmpty()){//队列非空结点未处理完毕
    HFMTreeNode tmp=q.poll();//节点出队
    if(!codes.startsWith(tmp.code)) continue;
    if(isLeaf(tmp)){//如果是叶子结点就计算编码长度
    str=str+tmp.name;
    codes=codes.substring(tmp.code.length());
    if(codes.length()>0){//如果存在多个报文字符,则继续重新编码、
    while(!q.isEmpty()) q.poll();
    q.add(data[root]);
    continue;
    }
    }
    if(tmp.lchild!=-1){//当前结点左孩子入队
    q.add(data[tmp.lchild]);
    }
    if(tmp.rchild!=-1){//当前结点右孩子入队
    q.add(data[tmp.rchild]);
    }
    
    }
return str;  
     }

}


你可能感兴趣的:(数据结构-java)