java实现文本的哈夫曼编码HuffmanTree(用数组的方式)

java数据结构实现文本的哈夫曼编码HuffmanTree(用数组的方式)

 •实验内容

1、读取文本Demo.txt。统计'a'-'z',空格,'.'的出现次数,并计算出权重。

2、根据字符及其权重构造Huffman树的节点  (Huffman节点需要的各个属性及相关方法)。

3、构造一个链表保存这些节点。

4、分两次从链表中找出权值最小的节点,生成一颗子树,并计算该子树的高度 (引入节点的Height属性)。

5、当链表中最后只剩一个节点时,就获得了Huffman树的根。

6、前序遍历Huffman树,遍历时构造Huffman编码(引入节点的编码属性)。

7、将特定文本翻译成Huffman编码对应的01串。

8、将上一步的01串通过Huffman树翻译成文本。

实现代码

1.设计Chars类

package 实验三;

public class Chars 
{
	char thechar;//文本中的字符
	float weight;//字符的权重
	int[] huffmancode;//哈弗曼树的编码
	int height;
	//构造方法,初始化,产生一个huffman编码
	Chars()
	{
		this.thechar='\0';
		this.weight=0.0f;
		this.huffmancode=null;
	}
	//获取字符
	public char getThechar() {
		return thechar;
	}
	//设置字符
	public void setThechar(char thechar) {
		this.thechar = thechar;
	}
	//获取权重
	public float getWeight() {
		return weight;
	}
	//设置权重
	public void setWeight(float weight) {
		this.weight = weight;
	}
	//获取huffmancode
	public int[] getHuffmancode() {
		return huffmancode;
	}
	//设置huffmancode
	public void setHuffmancode(int[] huffmancode) {
		this.huffmancode =huffmancode;
	}
	//toString()方法
	public String toString()
	{
		return "thechar:"+thechar+"	weight:"+weight+"	height:"+height+"	huffmancode:";
	}	
}

2.设计HuffmanList类 

package 实验三;

public class HuffmanList 
{
	HuffmanNode huffmanNode;
	float weight;
	int totalnodes;//连表头结点总数
	//链表中增加结点
	void addNode(HuffmanNode huffmanNode,float weight) 
	{
		this.huffmanNode=huffmanNode;
		this.weight=weight;
	}
}

3.设计HuffmanNode类 

package 实验三;

public class HuffmanNode implements Comparable<HuffmanNode>//Huffman树的结点类描述
{
	public float weight;// 结点的数据域
	public int height;//哈夫曼树的高度
	public int flag;//结点是否加入哈夫曼树的标志 
	public HuffmanNode parent,lchild,rchild;//父结点及左右孩子结点域
	char letter;//读入的字符
	int[] huffmancode;//读入字符编码 
	public HuffmanNode()//构造一个空结点
	{
		this.weight=0.0f;
		this.lchild=null;
		this.rchild=null;
		this.height=0;
		this.letter='\0';
		this.huffmancode=null;
	}
	
	public float getWeight() 
	{
		return weight;
	}

	public void setWeight(float weight)
	{
		this.weight = weight;
	}

	public int getHeight() 
	{
		return height;
	}

	public void setHeight(int height)
	{
		this.height = height;
	}

	public HuffmanNode getParent() 
	{
		return parent;
	}

	public void setParent(HuffmanNode parent) 
	{
		this.parent = parent;
	}

	public HuffmanNode getLchild()
	{
		return lchild;
	}

	public void setLchild(HuffmanNode lchild)
	{
		this.lchild = lchild;
	}

	public HuffmanNode getRchild() 
	{
		return rchild;
	}

	public void setRchild(HuffmanNode rchild) 
	{
		this.rchild = rchild;
	}

	public char getLetter() 
	
	{
		return letter;
	}

	public void setLetter(char letter) 
	{
		this.letter = letter;
	}

	public int[] getHuffmancode()
	{
		return huffmancode;
	}

	public void setHuffmancode(int[] huffmancode)
	{
		this.huffmancode = huffmancode;
	}
	//构造一个左、右孩子域为空,具有权值的结点
	public HuffmanNode(int weight)
	{
		this.weight=weight;
		flag=0;
		parent=lchild=rchild=null;
	}
	//构造一个带有字符和权重的结点
	public HuffmanNode(char letter,float weight)
	{
		this.letter=letter;
		this.weight=weight;
	}

	@Override
	//两结点权重比较,返回值为1或0或-1
	public int compareTo(HuffmanNode node) //比较权重是否相同
	{
		int result = 1;//初始result设置为1
		if(this.getWeight()>node.getWeight())//若当前权重大于比较的那个的权重,输出1
		{
			result=1;
		}
		else if(this.getWeight()<node.getWeight())//若当前权重小于比较的那个的权重,输出-1
		{
			result= -1;
		}
		else//当两个的权重相等的时候,则比较它们的深度
		{
			if(this.getWeight()>node.getHeight())//若当前深度大于比较的那个的深度,输出1
				result=1;
			else if(this.getHeight()<node.getHeight())//若当前深度小于比较的那个的深度,输出 -1
				result= -1;
		}
		return result;
	}
}

4.设计HuffmanTree 

package 实验三;


import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

public class HuffmanTree 
{
	char Chars[];//存放字符权重的数组
	HuffmanList Hlist;//链表
	
	//计算每个字符的最终权重(该字母出现次数/所有字符出现次数的总和),并存入HuffmanList中
    static void computeWeight(Chars[] chars)
    {
    	HuffmanList Hlink=new HuffmanList();//创建列表
		float totalWeight=0.0f;//总的权重
		for(int i=0;i<chars.length;i++)
		{//在链表的长度范围内
			//总权重=每个字符的权重相加
			totalWeight=totalWeight+chars[i].getWeight();
		}
		for(int i=0;i<chars.length;i++)
		{//在链表的长度范围内
			//第i个字符的权重=这个字符的出现次数/所有字符出现的次数
			chars[i].setWeight(chars[i].getWeight()/totalWeight);
			if(i<26)//小于26的时候,就是26个字母。起始是a,+1就变成b,+2就变成c,如此增加i,确定是哪个字母
				Hlink.addNode(new HuffmanNode('a'+i),chars[i].getWeight());
			if(i==26)//空格,排在26
				Hlink.addNode(new HuffmanNode(' '),chars[i].getWeight());
			if(i==27)//.排在27
				Hlink.addNode(new HuffmanNode('.'),chars[i].getWeight());
			if(i==28)//,排在28
				Hlink.addNode(new HuffmanNode(','),chars[i].getWeight());
		}
    }  
    
    //构建Huffman树
    int [][] conHuffmanTree(Chars[] chars)
	{
		int n=chars.length;//字符个数
		int m=2*n-1;//哈夫曼树的结点数
		HuffmanNode[] HN=new HuffmanNode[m];
		int i;
		//当i小于字符个数的时候,用一个HuffmanNode数组把各个结点给存起来
		for(i=0;i<n;i++)
		{
			HN[i]=new HuffmanNode();//构造n个具有权值的结点
			HN[i].letter=chars[i].thechar;//设置字符
			HN[i].weight=chars[i].weight;//设置权重
		}
		for(i=n;i<m;i++)//建造哈夫曼树
		{//每一次都把权值最小的那个结点拿进来构造树
			HuffmanNode min1=getMin(HN,i-1);
			min1.flag=1;//进树,flag=1
			HuffmanNode min2=getMin(HN,i-1);
			min2.flag=1;//进树,flag=1
			//构造min1和min2的父结点,并修改其父结点的权值
			HN[i]=new HuffmanNode();
			min1.parent=HN[i];
			min2.parent=HN[i];
			//min1和min2进行比较,小的放左边,大的放右边
			if(min1.compareTo(min2)==-1)
			{//当min1小于min2的时候
				HN[i].lchild=min1;
				HN[i].rchild=min2;
			}
			else//当min1大于min2的时候
			{
				HN[i].lchild=min2;
				HN[i].rchild=min1;
			}
			HN[i].weight=min1.weight+min2.weight;//父节点权值=左+右
			chars[i-28].height=getHeight(HN[i]);//设置高度
		}
		//从叶子到根逆向求每个字符的哈夫曼编码
		int[][] HuffCode=new int[n][n];//分配n个字符编码存储空间
		for(int j=0;j<n;j++)
		{
			int start=n-1;//编码的开始位置,初始化为数组的结尾
			for(HuffmanNode c=HN[j],p=c.parent;p!=null;c=p,p=p.parent)
			{
			//从叶子到根逆向求编码
		          if(p.lchild.equals(c))//左孩子编码为0
		        	  HuffCode[j][start--]=0;
		          else//(右孩子编码为1)
		        	  HuffCode[j][start--]=1;
				  HuffCode[j][start]=-1;//编码的开始标志为-1,编码是-1之后的0、1序列
			}
		}
		//当i小于字符个数的时候
		for(i=0;i<n;i++)
		{
			//第i个结点的huffmancode对应chars数组的第i个编码
			chars[i].huffmancode=HuffCode[i];
		}
		return HuffCode;//返回结点的数组
	}
	 //获得最小权重的结点
	static HuffmanNode getMin(HuffmanNode[] HN,int end)
	{	
		//先把最后一个默认为是权重最小的
		HuffmanNode min=HN[end];
		for(int i=0;i<=end;i++)
		{
			//用一个新的结点把第i个结点取出来进行权重大小的比较
			HuffmanNode h=HN[i];
			//不在哈夫曼树中且weight最小的结点
			if(h.flag==0&&h.weight<min.weight)
				min=h;
		}
		return min;//返回权值最小的结点
	}
	//获取高度
	public int getHeight(HuffmanNode node)
	{
	    if(node == null){
	        return 0;
	    }
	    int i = getHeight(node.lchild);
	    int j = getHeight(node.rchild);
	    return (i<j)? j+1:i+1;
	}
	//将读进来的文本以字符串形式接受
    public static String txt2String(File file)
    {
        StringBuilder result = new StringBuilder();
        try
        {
        	//构造一个BufferedReader类来读取文件
            BufferedReader br = new BufferedReader(new FileReader(file));
            String s = null;
            while((s = br.readLine())!=null)
            {//使用readLine方法,一次读一行
                result.append(System.lineSeparator()+s);
            }
            br.close();    
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        return result.toString();
    }
    
    
    public static void main(String[] args)
    {
    	HuffmanTree Huff=new HuffmanTree();
		Chars[] chars=new Chars[29];
		for(int i=0;i<chars.length;i++)
			chars[i]=new Chars();
		File txtfile =new File( "D:\\Demo\\Java\\eclipse\\DSPracticeDemo\\Demo.txt");//找到文件所在的位置
		try 
		{
			FileReader read=new FileReader(txtfile);	
	        int inputChar;
			while ((inputChar=read.read())!=-1) 
	        {
				//当字符是在a到z之间的时候
		    	if((inputChar>='a')&&(inputChar<='z'))
		    	{
		    		chars[inputChar-'a'].setThechar((char) inputChar);
		    		chars[inputChar-'a'].setWeight(chars[inputChar-'a'].getWeight()+1);//获取权重
		    	}
		    	//当字符为空格
		    	else if(inputChar==' ')
		    	{
		    		chars[26].setThechar(' ');
		    		chars[26].setWeight(chars[26].getWeight()+1);
		    	}
		    	//当字符为'.'
		    	else if(inputChar=='.')
		    	{
		    		chars[27].setThechar('.');
		    		chars[27].setWeight(chars[27].getWeight()+1);
		    	}
		    	//当字符为','
		    	else if(inputChar==',')
		    	{
		    		chars[28].setThechar(',');
		    		chars[28].setWeight(chars[28].getWeight()+1);
		    	}	
	        }
			computeWeight(chars);//算出权重
	    	//循环输出
			HuffmanTree T=new HuffmanTree();//构造哈夫曼树
	    	T.conHuffmanTree(chars);//求哈夫曼编码
	    	System.out.println("哈夫曼编码为:");
	    	for(int i=0;i<chars.length;i++)
	    	{	
	    		System.out.print("下标为:"+i+"		");
	    		System.out.print(chars[i]);
	    		//将特定文本翻译成Huffman编码对应的01串。
	    		for(int j=0;j<chars[i].huffmancode.length;j++)
				{
					 if(chars[i].huffmancode[j]==-1)//开始标识符读到数组结尾
		    		    {
		    			    for(int k=j+1;k<chars[i].huffmancode.length;k++)
		    			        System.out.print(chars[i].huffmancode[k]);//输出
		    			    break;
		    		    }
				}
				System.out.println();
	    	}	
	    	//将特定文本翻译成Huffman编码对应的01串。
	    	System.out.print("将特定文本翻译成Huffman编码对应的01串:");
		    String str=txt2String(txtfile);
		    //System.out.println(str);
		    //将字符串转为数组
		    char[] array = str.toCharArray();
		    int maxsize=array.length;//最大的长度
		    int[] codeArray=new int[maxsize];//建一个数组,用来存放编码
		    int codestr = 0;
		    //输出a
		    for(int l=0;l<array.length;l++)
		    {
		    	for(int m=0;m<chars.length;m++)
		    	{
					if(array[l]==(chars[m].thechar))
					{
						for(int j=0;j<chars[m].huffmancode.length;j++)
						{
							 if(chars[m].huffmancode[j]==-1)//开始标识符读到数组结尾
					    	 {
					    		  for(int k=j+1;k<chars[m].huffmancode.length;k++)
					    		 {
					    				 codeArray[l]=chars[m].huffmancode[k];//编码存进去数组中
					    			     //System.out.print(chars[m].huffmancode[k]);//输出
					    				 System.out.print(codeArray[l]);
					    		 }
					    		break;
					    	 }
						}
					}
		    	}
	    		if(l%20==0)//一行输出20个就好了
	    			System.out.println();
		    }
		    System.out.println("");
	    	//将上一步的01串通过Huffman树翻译成文本。
			System.out.print("将上一步的01串通过Huffman树翻译成文本:");
			//输出
			 for(int q=0;q<array.length;q++)
			    {
			    	for(int m=0;m<chars.length;m++)
			    	{
						if(array[q]==(chars[m].thechar))
						{
							for(int j=0;j<chars[m].huffmancode.length;j++)
							{
								 if(chars[m].huffmancode[j]==-1)//开始标识符读到数组结尾
						    	 {
						    		  for(int k=j+1;k<chars[m].huffmancode.length;k++)
						    		 {
						    				codeArray[q]=chars[m].huffmancode[k];//编码存进去数组中
						    				codestr=chars[m].huffmancode[k];
						    		 }
						    			if(codeArray[q]==codestr)
						    			{
						    				System.out.print(chars[m].thechar);
						    			}
						    		break;
						    	 }
							}
						}
			    	}
		    		if(q%100==0)//一行输出100个就好了
		    			System.out.println();
			    }
			 //Chars[] charsSingle=Huff.getContext(txtfile);	//获取数据
			read.close();
		}
		catch (Exception e)
		{
		    System.out.println(e.toString());
		}
    }
}

5.测试类 

package 实验三;

import java.io.File;
import java.io.FileReader;


public class Test 
{
	 public static void main(String[] args)
	    {
	    	HuffmanTree Huff=new HuffmanTree();
			Chars[] chars=new Chars[29];
			for(int i=0;i<chars.length;i++)
				chars[i]=new Chars();
			File txtfile =new File( "D:\\Demo\\Java\\eclipse\\DSPracticeDemo\\Demo.txt");//找到文件所在的位置
			try 
			{
				FileReader read=new FileReader(txtfile);	
		        int inputChar;
				while ((inputChar=read.read())!=-1) 
		        {
					//当字符是在a到z之间的时候
			    	if((inputChar>='a')&&(inputChar<='z'))
			    	{
			    		chars[inputChar-'a'].setThechar((char) inputChar);
			    		chars[inputChar-'a'].setWeight(chars[inputChar-'a'].getWeight()+1);//获取权重
			    	}
			    	//当字符为空格
			    	else if(inputChar==' ')
			    	{
			    		chars[26].setThechar(' ');
			    		chars[26].setWeight(chars[26].getWeight()+1);
			    	}
			    	//当字符为'.'
			    	else if(inputChar=='.')
			    	{
			    		chars[27].setThechar('.');
			    		chars[27].setWeight(chars[27].getWeight()+1);
			    	}
			    	//当字符为','
			    	else if(inputChar==',')
			    	{
			    		chars[28].setThechar(',');
			    		chars[28].setWeight(chars[28].getWeight()+1);
			    	}	
		        }
				Huff.computeWeight(chars);//算出权重
		    	//循环输出
				HuffmanTree T=new HuffmanTree();//构造哈夫曼树
		    	T.conHuffmanTree(chars);//求哈夫曼编码
		    	System.out.println("哈夫曼编码为:");
		    	for(int i=0;i<chars.length;i++)
		    	{	
		    		System.out.print("下标为:"+i+"		");
		    		System.out.print(chars[i]);
		    		//将特定文本翻译成Huffman编码对应的01串。
		    		for(int j=0;j<chars[i].huffmancode.length;j++)
					{
						 if(chars[i].huffmancode[j]==-1)//开始标识符读到数组结尾
			    		    {
			    			    for(int k=j+1;k<chars[i].huffmancode.length;k++)
			    			        System.out.print(chars[i].huffmancode[k]);//输出
			    			    break;
			    		    }
					}
					System.out.println();
		    	}	
		    	//将特定文本翻译成Huffman编码对应的01串。
		    	System.out.print("将特定文本翻译成Huffman编码对应的01串:");
			    String str=Huff.txt2String(txtfile);
			    //System.out.println(str);
			    //将字符串转为数组
			    char[] array = str.toCharArray();
			    int maxsize=array.length;//最大的长度
			    int[] codeArray=new int[maxsize];//建一个数组,用来存放编码
			    int codestr = 0;
			    //输出a
			    for(int l=0;l<array.length;l++)
			    {
			    	for(int m=0;m<chars.length;m++)
			    	{
						if(array[l]==(chars[m].thechar))
						{
							for(int j=0;j<chars[m].huffmancode.length;j++)
							{
								 if(chars[m].huffmancode[j]==-1)//开始标识符读到数组结尾
						    	 {
						    		  for(int k=j+1;k<chars[m].huffmancode.length;k++)
						    		 {
						    				 codeArray[l]=chars[m].huffmancode[k];//编码存进去数组中
						    			     //System.out.print(chars[m].huffmancode[k]);//输出
						    				 System.out.print(codeArray[l]);
						    		 }
						    		break;
						    	 }
							}
						}
			    	}
		    		if(l%50==0)//一行输出50个就好了
		    			System.out.println();
			    }
			    System.out.println("");
		    	//将上一步的01串通过Huffman树翻译成文本。
				System.out.print("将上面的01串通过Huffman树翻译成文本:");
				//输出
				 for(int q=0;q<array.length;q++)
				    {
				    	for(int m=0;m<chars.length;m++)
				    	{
							if(array[q]==(chars[m].thechar))
							{
								for(int j=0;j<chars[m].huffmancode.length;j++)
								{
									 if(chars[m].huffmancode[j]==-1)//开始标识符读到数组结尾
							    	 {
							    		  for(int k=j+1;k<chars[m].huffmancode.length;k++)
							    		 {
							    				codeArray[q]=chars[m].huffmancode[k];//编码存进去数组中
							    				codestr=chars[m].huffmancode[k];
							    		 }
							    			if(codeArray[q]==codestr)
							    			{
							    				System.out.print(chars[m].thechar);
							    			}
							    		break;
							    	 }
								}
							}
				    	}
			    		if(q%150==0)//一行输出150个就好了
			    			System.out.println();
				    }
				read.close();
			}
			catch (Exception e)
			{
			    System.out.println(e.toString());
			}
	    }
}

 运行结果:

  一枚平平无奇的小白!~

  欢迎相互学习!~ 

  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 17
    评论
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值