1.Huffman设计了一个贪心算法来构造最优前缀码,可以有效地压缩数据,按频率(大小)来编码。
2.构造huffman树最普通的算法是每次选出两个最小的元素作为它的左右子树。依次从叶节点向上回溯,即可构造一棵huffman树。
3基于上面的思想,由于每次选出两个最小的元素,可以用到最小堆的性质在O(logn)时间内找最小的元素。(优先队列就是靠最小堆(最大堆)实现的)。
</pre></p><p>1.普通算法</p><pre code_snippet_id="537518" snippet_file_name="blog_20141130_2_9111669" name="code" class="java">package datastructure;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.Scanner;
/**
*
*暑假作业(Huffman树,以及Huffman编码)
*@author ChenHaiJun
*@date 2014年7月21日
*@version 1.7
*/
public class HuffmanTree {
private Huffman[] hm;
private int[][] huffmanCode;
private int size;
private int node;
class Huffman{
public int getParent() {
return parent;
}
public void setParent(int parent) {
this.parent = parent;
}
public int getRchild() {
return rchild;
}
public void setRchild(int rchild) {
this.rchild = rchild;
}
public int getLchild() {
return lchild;
}
public void setLchild(int lchild) {
this.lchild = lchild;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
int parent;
int rchild;
int lchild;
int weight;
boolean flag;
public Huffman(){
parent=-1;
rchild=-1;
lchild=-1;
weight=0;
flag=false;
}
}
public HuffmanTree(int n){
node=n;
hm=new Huffman[2*node];
huffmanCode=new int[2*node][node];
for(int i=0;i<2*node;i++){
Arrays.fill(huffmanCode[i], -1);
}
size=node;
}
/**
* 该算法利用了贪心思想(最优子结构)
* 但算法复杂度为O(n^2)
*/
public void createHuffmanTree(){
System.out.println("输入"+node+"个点的权值:");
for(int i=1;i<=node;i++){
hm[i]=new Huffman();
hm[i].weight=getInt();
}
int min1,min2,j;
hm[0]=new Huffman();
hm[0].weight=Integer.MAX_VALUE;
for(int i=1;i<node;i++){
min1=min2=0;
for(j=1;j<=size;j++){
if(hm[j].weight<hm[min1].weight&&(!hm[j].flag)){
min1=j;
}
}
hm[min1].flag=true;
for(j=1;j<=size;j++){
if(hm[j].weight<hm[min2].weight&&(!hm[j].flag)){
min2=j;
}
}
hm[min2].flag=true;
size++;
hm[size]=new Huffman();
hm[size].weight=hm[min1].weight+hm[min2].weight;
hm[size].lchild=min1;
hm[size].rchild=min2;
hm[min1].parent=size;
hm[min2].parent=size;
}
}
public int getHuffmanWeigt(){
int j,l;
int[] weight=new int[node+1];
for(int i=1;i<=node;i++){
j=i;
l=0;
while(hm[j].parent!=-1){
l++;
j=hm[j].parent;
}
weight[i]=l*hm[i].weight;
}
int sum=0;
for(int i=1;i<=node;i++){
sum+=weight[i];
}
return sum;
}
public void huffmanCode(){
int j,k,index;
int[] code=new int[node];
for(int i=1;i<=node;i++){
j=i;
index=-1;
while(hm[j].parent!=-1){
k=j;
j=hm[j].parent;
index++;
if(hm[j].lchild==k){
code[index]=0;
}
else{
code[index]=1;
}
}
for(j=index;j>=0;j--){
huffmanCode[i][index-j]=code[j];
}
}
}
public void showHuffmanTree(){
for(int i=1;i<=node;i++){
int j=0;
System.out.print("hm["+i+"]="+hm[i].weight+" Code:");
while(huffmanCode[i][j]!=-1){
System.out.print(huffmanCode[i][j]);
j++;
}
System.out.println("");
}
}
public static int getInt(){
Scanner sc=new Scanner(System.in);
return sc.nextInt();
}
public static void main(String[] args){
System.out.println("输入哈夫曼的叶结点个数:");
int n=getInt();
HuffmanTree tree=new HuffmanTree(n);
tree.createHuffmanTree();
tree.huffmanCode();
tree.showHuffmanTree();
System.out.println("HuffmanTree的权重:"+tree.getHuffmanWeigt());
}
}
2.改进算法:
package datastructure;
import java.util.PriorityQueue;
import java.util.Scanner;
public class HuffmanTree2 {
private Node root=new Node();
private boolean[] code=new boolean[100];
private PriorityQueue<Node> queue=new PriorityQueue<Node>();
private class Node implements Comparable<Node>{
private Node lChild;
private Node rChild;
private int data;
public Node(int data) {
super();
this.data = data;
}
public Node(){
}
public Node getlChild() {
return lChild;
}
public void setlChild(Node lChild) {
this.lChild = lChild;
}
public Node getrChild() {
return rChild;
}
public void setrChild(Node rChild) {
this.rChild = rChild;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
@Override
public int compareTo(Node o) {
return this.data-o.getData();
}
}
/**
* 构造huffman树
* 算法是贪心算法,有优先队列实现
*/
public void createHuffmanTreee(){
int nodeCount=0;
System.out.print("请输入节点的个数:");
nodeCount=getInt();
System.out.print("输入"+nodeCount+"个点的权值:");
for(int i=1;i<=nodeCount;i++){
Node node=new Node(getInt());
node.lChild=null;
node.rChild=null;
queue.add(node);
}
Node lchild=null;
Node rchild=null;
while(true){
lchild=queue.poll();
rchild=queue.poll();
if(queue.isEmpty()) break;
Node tmp=new Node();
tmp.setData(lchild.data+rchild.data);
tmp.lChild=lchild;
tmp.rChild=rchild;
queue.add(tmp);
}
root.data=lchild.data+(rchild!=null?rchild.data:0);
root.lChild=lchild;
root.rChild=rchild;
}
/**
* 打印huffman编码
* 左边的位0,右边的位1
* @return
*/
public void huffmanCode(Node root,int pos){
if(root==null){
throw new IllegalArgumentException("树根不能为空");
}
if(root.lChild!=null){
code[pos]=false;
huffmanCode(root.lChild,pos+1);
}
if(root.rChild!=null){
code[pos]=true;
huffmanCode(root.rChild,pos+1);
}
if(root.lChild==null||root.rChild==null){
System.out.print(root.data+":");
for(int i=0;i<pos;i++){
System.out.print(code[i]?1:0);
}
System.out.println("");
}
}
public static int getInt(){
Scanner sc=new Scanner(System.in);
return sc.nextInt();
}
public static void main(String[] args){
HuffmanTree2 tree=new HuffmanTree2();
tree.createHuffmanTreee();
tree.huffmanCode(tree.root,0);
}
}