天天看点

哈夫曼树,编码,解码

思路:使用Scanner接受屏幕输入,在这里,仅限连续的小写字母

          求出不同字母在上述Scanner输入中,出现的次数。           比如字母a(如果有),出现几次,b(如果有),出现几次……

          根据不同字母出现的次数(权值),构建哈夫曼树

          得到每个字母对应的路径,即可生成哈夫曼编码

          对已有的哈夫曼编码,采取从头开始截取编码

          长度从1开始,如果截取下来的编码与某个字母匹配,则去掉这个截取的编码           继续截取新的编码,长度从1开始,到2,到3,直到截取的字符串与某个字母匹配……           继续上述操作,最后得到原先的连续的小写字母

package fifty;

public class Node {
	Node leftNode;
	Node rightNode;
	int data;
	char zifu;
	
	public Node(){
		leftNode = null;
		rightNode = null;
		data = 0;
		zifu = 'a';
	}
}
           
package fifty;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;

public class HuffmanCoding {
	static List<String[]> qlist = new ArrayList<String[]>();
	//qlist里某个数组内元素个数
	public static int getCnt(String[] s){
		int n = 0;
		for(int i = 0; i < s.length; i++)
		{
			if(null != s[i]) 
				n++;
		}
		return n;
	}
	//每条路径装在一个数组里,每个数组装在qlist里
	private static void printPaths(Node node, String[] path, 
			int pathLen){
		if(node == null){
			return;
		}
		path[pathLen++] = /*Character.toString(node.zifu)*/
				Integer.toString(node.data);
		if(node.leftNode == null
				&& node.rightNode == null){
			//System.out.print(node.zifu+":");
			//printArray(node, path, pathLen);
			path[0] = Character.toString(node.zifu);
			String[] s = new String[path.length];
			for(int m = 0; m < path.length; m++){
				s[m] = path[m];
			}
			qlist.add(s);
		}else{
			printPaths(node.leftNode, path, pathLen);
			printPaths(node.rightNode, path, pathLen);
		}
	}
	//求最小值
	public static int[] getMinInt(List<Integer> list){
		int[] min = new int[2];
		min[1] = (int) Collections.min(list);
		min[0] = list.indexOf(min[1]);
		list.remove(list.indexOf(min[1]));
		return min;
	}
	//求根节点的值最小的两棵树
	public static Node[] getMinInt2(List<Node> list){
		List<Integer> newlist = new ArrayList<Integer>();
		int[] min2 = new int[2];
		Node[] newtree = new Node[2];
		
		for(int m = 0; m < list.size(); m++){
			newlist.add(list.get(m).data);
		}
		min2 = getMinInt(newlist);
		newtree[0] = list.get(min2[0]);
		list.remove(list.indexOf(newtree[0]));
		
		min2 = getMinInt(newlist);
		newtree[1] = list.get(min2[0]);
		list.remove(list.indexOf(newtree[1]));

		return newtree;
	}
	//获取左节点
	public static Node getLeftNode(Node node){
		return node.leftNode;
	}
	//获取右节点
	public static Node getRightNode(Node node){
		return node.rightNode;
	}
	//节点总数
	public static int sumNode(Node node){
		if(node == null){
			return 0;
		}else{
			int a = sumNode(getLeftNode(node));
			int b = sumNode(getRightNode(node));
			return 1+a+b;
		}
	}
	//主函数
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		String input;
		System.out.println("输入(仅限连续的小写字母):");
		input = scanner.next();
		/*String[] shuzu = new String[100];
		for(int m = 0; m <= input.length()-1; m++){
			shuzu[m] = Character.toString(input.charAt(m));
		}*/
		int[] countabc = new int[26];
		for(int m = 0; m <=input.length()-1; m++){
			char c = input.charAt(m);
			int index = c-'a';
			countabc[index] = countabc[index]+1;
		}
		
		List<Integer> list = new ArrayList<>();
		List<Character> charlist = new ArrayList<Character>();
		
		int count = 0;
		for(int m = 0; m < countabc.length; m++){
			if(countabc[m] != 0){
				list.add(countabc[m]);
				charlist.add((char)(m+'a'));
				count++;
				System.out.println((char)(m+'a')
						+":"+countabc[m]+"次");
			}
		}
		System.out.println("字母种类:"+count);
		//构建二叉树
		Node[] node = new Node[count];
		//赋值给每棵树的根节点
		for(int m = 0; m < count; m++){
			node[m] = new Node();
			node[m].data = list.get(m);
			node[m].zifu = charlist.get(m);
		}
		List<Node> otherlist = new ArrayList<Node>();
		for(int m = 0; m < count; m++){
			otherlist.add(node[m]);
		}
		Node[] tempnode = new Node[2];
		//newlist用于存储旧树新树
		List<Node> newlist = new ArrayList<Node>();
		//while循环,构建哈夫曼树
		while(otherlist.size() != 1){
			tempnode = getMinInt2(otherlist);
			Node newnode = new Node();
			newlist.add(tempnode[0]);
			newlist.add(tempnode[1]);
			newnode.data = tempnode[0].data + 
					tempnode[1].data;
			newnode.leftNode = tempnode[0];
			newnode.leftNode.data = 0;
			newnode.rightNode = tempnode[1];
			newnode.rightNode.data = 1;
			otherlist.add(newnode);
		}
		Node lastnode = otherlist.get(0);
		newlist.add(lastnode);	//最后一棵树加上去
		int num = sumNode(lastnode);
		System.out.println("节点个数:"+num);
/*		Node[] node_shuzu = new Node[num];
		for(int m = 0; m < num; m++){
			node_shuzu[m] = newlist.get(m);
			if(node_shuzu[m].leftNode == null
					&& node_shuzu[m].rightNode == null){
				System.out.println(node_shuzu[m].data+"和"+node_shuzu[m].zifu+"和数组下标"+m);
			}
		}
*/		String[] path = new String[sumNode(lastnode)];
		printPaths(lastnode, path, 0);
		System.out.println("对应路径:");
		for(int m = 0; m < qlist.size(); m++){
			for(int n = 0; n < getCnt(qlist.get(m)); n++){
				System.out.print(qlist.get(m)[n]);
			}
			System.out.println();
		}
		System.out.print("哈夫曼编码:");
		List<String> numlist = new ArrayList<String>();//存储哈夫曼编码
		for(int m = 0; m < input.length(); m++){
			for(int i = 0; i < qlist.size(); i++){
				if(Character.toString(input.charAt(m)).equals(qlist.get(i)[0])){
					for(int n = 1; n < getCnt(qlist.get(i)); n++){
						numlist.add(qlist.get(i)[n]);
						System.out.print(qlist.get(i)[n]);
					}
				}
			}
		}
		//numlist转换成字符串
		String huffmanstr = numlist.toString();
		huffmanstr = huffmanstr.substring(1, huffmanstr.length()-1);
		huffmanstr = huffmanstr.replaceAll("[,]", "");
		huffmanstr = huffmanstr.replaceAll("[ ]", "");
		System.out.println();
		System.out.println("huffmanstr长度:"+huffmanstr.length());
		System.out.print("numlist输出:");
		for(int m = 0; m < numlist.size(); m++){
			System.out.print(numlist.get(m));
		}
		System.out.println();
		List<String> zlist = new ArrayList<String>();
		for(int n = 0; n < qlist.size(); n++){
			List<String> templist = new ArrayList<String>();
			String s = null;
			for(int m = 0; m < getCnt(qlist.get(n)); m++){
				templist.add(qlist.get(n)[m]);
				s = templist.toString();
				s = s.substring(1, s.length()-1);
				s = s.replaceAll("[,]", "");
				s = s.replaceAll("[ ]", "");
			}
			zlist.add(s);
		}
		System.out.println("zlist输出:");
		for(int m = 0; m < zlist.size(); m++){
			System.out.println(zlist.get(m));
		}
		System.out.println("解码后得到:");
		while(huffmanstr != null){
			for(int m = 0; m < zlist.size(); m++){
				inter:for(int n = 1; n <= huffmanstr.length(); n++){
					if((huffmanstr.substring(0, n))
							.equals(zlist.get(m).substring(1,zlist.get(m).length()))){
						System.out.print(Character.toString(zlist.get(m).charAt(0)));
						huffmanstr = huffmanstr.substring(n, huffmanstr.length());
						continue inter;
					}
				}
			}
		}
		scanner.close();
	}
}