哈夫曼编码小结

哈夫曼树
哈夫曼树是一最优二叉树,假设有n个字节点Tn{T1,T2,……,Tn}的权值分别为
Wn{W1,W2,……,Wn},其构造方法
step1:想找出里面权值最小的两个节点,作为新建父节点的左右子树,父节点的权值step2:为这两个子节点的权值之和在Tn中将父节点的左右子树删除,并将父节点加进step3:重复1、2步,直到Tn只剩一个节点为止。
哈夫曼编码:当建好树后,从根开始,每层左子树标记为0,右子树标记为1,按此规律索引到叶节点,此顺序的01串即为该叶节点对应的哈夫曼编码。
下面是我的建树和打印哈夫曼编码过程(实现了简单的解码):


public class HalfmanTree {
	//key字符为value为字符的哈夫曼编码的map队列
	HashMap<String, String> map_pre= new HashMap<String, String>();
	//key字符为哈夫曼编码为字符的value的map队列,解码用的
	HashMap<String, String> map_dis= new HashMap<String, String>();
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		//String str="abbcccddddeeeee";
		//手动输入字符串
		Scanner sc=new Scanner(System.in);
		String str=sc.nextLine();
		//创建一个哈夫曼类
		HalfmanTree half=new HalfmanTree();
		//把字符串按不同字符统计权值,并存储到结点类数组中
		TreeNode [] arraynode=half.countstr(str);
		//根据结点类数组建立树
		TreeNode n=half.settree(arraynode);
		//打印叶节点中字符的哈夫曼编码,并已将编码放入map中
		half.print_hfm(n, "");
		
		//打印字符串的哈夫曼编码
		half.print_01(str);
		//打印解码的map
		half.print_map_dis();
		//打印解码后的字符串
		//System.out.println(half.discover_code("000 001	001	01	01	01	10	10	10	10	11	11	11	11	11"));
		
				
	} //主函数结束
	
	//以树节点中的权值大小为标准的比较器
	Comparator<TreeNode> com=new Comparator<TreeNode>() {
		@Override
		public int compare(TreeNode o1, TreeNode o2) {
			// TODO Auto-generated method stub
			if(o1.date>o2.date){
				return 1;
			}
			else
				return -1;
		}
	};
	
	//对字符串进行遍历,以各不同字符及对应权值创建结点类,保存到数组中返回
	public TreeNode [] countstr(String str){
		boolean flag_ever;//字符串重复标志
		//把第一个字符存入结点类队列的第一个
		ArrayList<TreeNode> listnode=new ArrayList<TreeNode>();	
		
		TreeNode node =new TreeNode();
		node.c=str.charAt(0);
		node.date=1;
	 	listnode.add(node);

		//从第二个开始遍历字符串
		for(int i=1;i<str.length();i++){
			flag_ever=false;
			//得到第i个字符
			char c=str.charAt(i);
			//遍历结点类队列
			for(int j=0;j<listnode.size();j++){
				//如果这个字符存在某个结点类中
				if(c==listnode.get(j).c){
					//把该几点权值计数加1
					listnode.get(j).date++;
					flag_ever=true;
					//结束循环
					break;
				}
			}
			//如果重复标志还是false,则表示没有重复的
			if(flag_ever==false){
				//那么应该新建一个节点,加入队列中
				TreeNode newnode =new TreeNode();
				newnode.c=c;
				newnode.date=1;
			 	listnode.add(newnode);
			 	//System.out.println(listnode.size());
			}
		}
		
		//将节点类队列的节点存到数组中
		TreeNode [] arraynode=new TreeNode[listnode.size()];
		for(int i=0;i<arraynode.length;i++){
			arraynode[i]=listnode.get(i);
//			System.out.println(listnode.get(i).c);
//			System.out.println(listnode.get(i).date);
		}
		
		return arraynode;
	}
	
	
	//由结点类数组创建一个树,返回根节点
	public TreeNode settree(TreeNode node_array[]){
		//直到只有一个节点时结束
		while(node_array.length>1){
			//对数组进行排序,按照com比较器
			Arrays.sort(node_array, com);
			//由最小两个数的所在节点创建父节点
			TreeNode node=new TreeNode();
			node.left=node_array[0];
			node.right=node_array[1];
			node.date=node_array[0].date+node_array[1].date;
			//创建新节点数组,长度减一
			TreeNode[] newnode_array=new TreeNode[node_array.length-1];
			for(int i=2;i<node_array.length;i++){
				newnode_array[i-2]=node_array[i];
			}
			newnode_array[node_array.length-2]=node;
			//把新节点数组首地址赋给院节点数组
			node_array = newnode_array;
		}
		//最后一个节点即根节点,赋哈夫曼编码,并返回根节点
		node_array[0].s="";
		return node_array[0];
	}
	
	//打印二叉树编码
	public void print_hfm(TreeNode node,String  code){
		//有节点存在时
		if(node!=null){
			
//			if(node.left ==null && node.right==null){
//			System.out.println(node.c+"的哈夫曼编码为:"+code);
//	
//			}
//			print_hfm(node.left, code+"0");
//			print_hfm(node.right, code+"1");
			//该节点为叶子节点时
			if(node.left ==null && node.right==null){
				System.out.println(node.c+"的哈夫曼编码为:"+node.s+" 权数为:"+node.date);
				map_pre.put(""+node.c, node.s);
				map_dis.put(node.s,""+node.c);
				
			}
			//左子树为空时,打印哈夫曼编码
			if(node.left!=null){
				node.left.s=node.s+"0";
				print_hfm(node.left,node.left.s);
			}
			//右子树为空时,打印哈夫曼编码
			if(node.right!=null){
				node.right.s= node.s+"1";
				print_hfm(node.right,node.right.s);
			}
			
		}
		
	}
	//按字符输出哈夫曼编码
	public void print_01(String str){
		System.out .println(str+"各字符对应编码为:");
		for(int i=0;i<str.length();i++){
			char ch= str.charAt(i);
			String code=map_pre.get(""+ch);
			System.out.print(code+'\t');//每个编码直接加tab键间隔
		}
		System.out .println();
	}
//测试打印map_dis
	public void print_map_dis (){
		Set<Entry<String, String>> entry=map_dis.entrySet();
		for(Entry<String, String> en : entry ){
			System.out.println("键"+en.getKey()+"的值为:"+en.getValue());
		}
	}
	//解码
	public String discover_code(String str_str){
		//String str="000001";
		String discode="";
		Set<String> set=map_dis.keySet();
		String s="";
		for(int i=0;i<str_str.length();i++){
			if(str_str.charAt(i)!='\t'&&str_str.charAt(i)!=' '){
				System.out.println(i);
				s=s+str_str.charAt(i);
				for(String ss :set){
					if(s.equals(ss)){
						discode=discode+map_dis.get(s);
						s="";
						break;
					}
				}
			}
			
		}
		return discode;
	}
	
}




这只是个简单的给哈夫曼树编码,应用的话可以做个解约软件,有待突破!!!!

你可能感兴趣的:(java,数据结构,哈夫曼树)