赫夫曼编码的JAVA实现及其分析

几个问题:

1,没有构造出真正的赫夫曼树,最后结果需要自己手动画出来;
2,针对于某一类中的set和get方法,每次都忘了用,最后才是反应过来强行加上的,说到底还是代码规范问题,同时也可以理解为封装特性,有个坏习惯,每次总是直接的去访问成员变量。
3,自动生成重写一个类的toString方法时,Ecplise会报以下错。查了查说是JDK9和Ecplise有冲突??

赫夫曼编码的JAVA实现及其分析_第1张图片



话不多说直接开始。

一:首先建立一个关于结点的类,用于维护该结点的相关信息。

class nodeinf {
	/**
	 * nodeinf用来维护该节点的相关信息
	 * @param name名字
	 * @param fre频率
	 * @param left左孩子名字
	 * @param right右孩子名字
	 */
	private String name;
	private int fre;
	private String left;
	private String right;
	public nodeinf(String name,int fre) {
		this.name=name;
		this.fre=fre;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getFre() {
		return fre;
	}
	public void setFre(int fre) {
		this.fre = fre;
	}
	public String getLeft() {
		return left;
	}
	public void setLeft(String left) {
		this.left = left;
	}
	public String getRight() {
		return right;
	}
	public void setRight(String right) {
		this.right = right;
	}
	@Override
	public String toString() {  
        return "name="+this.name+"\tfre="+this.fre+"\tleft="+this.left+"\tright="+this.right;  
    }  
}

其中的tostring方法是重写的,方便用于打印某一结点的信息。

二:再次想到huffman code其中蕴含着贪心算法的思想,贪心算法是怎样体现的呢。

每次按照频率升序排序,选择前两个结点进行组合。看似是单纯的对于结点的排序,但实际上是针对于nodeinf对象排序的。针对对象排序,我们可以想到利用比较器。这里我选择Comparator比较器(为什么我也不知道,比较器这部分后面还是需要再看看)。

/**
 * 利用比较器实现按fre频率升序排序
 * @author Oliver
 *
 */
class mycomparator implements Comparator{

	@Override
	public int compare(nodeinf arg0, nodeinf arg1) {
		// TODO Auto-generated method stub
		return arg0.getFre()-arg1.getFre();
	}
	
}

三:huffman编码的核心部分。

一次循环:首次排序后,将下标为0、1的元素整合,整合之后新结点为父节点,父节点的频率为两者相加,同时进行赋值操作以维护当前父节点的左右孩子了。然后再进行下一个循环。

如何实现上述过程,不妨用一个ArrayList来保存所有结点。0、1元素整合之后再删除,然后将新的父节点加入进去到这个ArrayList中去,再进行排序。直到我们的集合长度为1时,表示根节点已经形成。下面的最后一张图也就是集合长度为1的情况。

赫夫曼编码的JAVA实现及其分析_第2张图片

赫夫曼编码的JAVA实现及其分析_第3张图片

每次我都用左右两个孩子的名字相加得到父节点的名字,这样会更加直观的看到其中过程。

代码:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

/**
 * 赫夫曼编码的实现
 * @author Oliver
 *
 */
public class Huffman_Implement {

	public static void main(String[] args) {
		ArrayList list=new ArrayList<>();
		Huffman_Implement test=new Huffman_Implement();
		
		nodeinf node1=new nodeinf("a",45);
		nodeinf node2=new nodeinf("b",13);
		nodeinf node3=new nodeinf("c",12);
		nodeinf node4=new nodeinf("d",16);
		nodeinf node5=new nodeinf("e",9);
		nodeinf node6=new nodeinf("f",5);
		list.add(node1);
		list.add(node2);
		list.add(node3);
		list.add(node4);
		list.add(node5);
		list.add(node6);
		
		System.out.println("-----------------实现huffman code之前-----------------");
		test.print(list);
		System.out.println("---------------------最后根节点为:---------------------\n"+test.createTree(list));
	}
	/**
	 * 构造赫夫曼树
	 * @param list
	 * @return
	 */
	private nodeinf createTree(ArrayList list) {
		while(list.size()>1) {
			sort(list);
			nodeinf left=list.get(0);
			nodeinf right=list.get(1);
			//"+"操作符重载啦
			nodeinf pre=new nodeinf(list.get(0).getName()+list.get(1).getName(),
					                list.get(0).getFre()+list.get(1).getFre());
			pre.setLeft(left.getName());
			pre.setRight(right.getName());
			//因为第一个remove(0)执行后,可以理解为List立即将所有元素向前推一个,所以要再执行一次remove(0),而不是remove(1)
			list.remove(0);
			list.remove(0);
			list.add(pre);
		}
		return list.get(0);
	}
	/**
	 * 排序方法
	 * @param list
	 */
	private void sort(ArrayList list) {
		Collections.sort(list, new mycomparator());
		System.out.println("---------------------一次排序后---------------------");
		print(list);
	}
	/**
	 * 打印方法
	 * @param list
	 */
	private void print(ArrayList list) {
		for(nodeinf node:list) {
			System.out.println(node.toString());
		}
	}

}

执行结果:

赫夫曼编码的JAVA实现及其分析_第4张图片

其中可以从根节点中直接可以看到,名字的顺序就是从左到右的叶子结点。

你可能感兴趣的:(算法导论)