1.字符结点类CharNode,用于封装一个字符的值和它出现的频率
CharNode.java
//字符结点类,用于封装一个字符的值和它出现的频率
public class CharNode {
private char c;
private int freq;
public CharNode(char c, int freq) {
this.c = c;
this.freq = freq;
}
public char getC() {
return c;
}
public void setC(char c) {
this.c = c;
}
public int getFreq() {
return freq;
}
public void setFreq(int freq) {
this.freq = freq;
}
public String toString() {
return "字符:"+this.c+",出现频率:"+this.freq;
}
}
2.赫夫曼树的结点类Node,对应书中的Node,用于将字符转换为符合赫夫曼树中的Node类。
除了和书中一样的属性外,为了保证编码搜索路径显示的方便,Node类增加了一个属性标记信号sign,只有两个值:0或1,若在构建赫夫曼二叉树的过程中该节点为左节点,则sign=0,反之,sign=1
Node.java
//赫夫曼树的结点类,用于字符转换为Node
public class Node implements Comparable<Node>{
private char charValue;//保存了字符值
private int freq;//保存字符出现的频率
private Node left;//左子节点
private Node right;//右子节点
private int sign;//标记信号,只有两个值:0或1,若在构建赫夫曼二叉树的过程中该节点为左节点,则sign=0,反之,sign=1
public Node() {
}
public Node(CharNode charnode) {
this.charValue = charnode.getC();
this.freq = charnode.getFreq();
this.sign = 0;//初始化的结点sign都是0
}
public char getCharValue() {
return this.charValue;
}
public void setCharValue(char charValue) {
this.charValue = charValue;
}
public int getFreq() {
return this.freq;
}
public void setFreq(int freq) {
this.freq = freq;
}
public Node getLeft() {
return this.left;
}
public void setLeft(Node left) {
this.left = left;
}
public Node getRight() {
return this.right;
}
public void setRight(Node right) {
this.right = right;
}
public int getSign() {
return sign;
}
public void setSign(int sign) {
this.sign = sign;
}
@Override
public int compareTo(Node newNode) {
if(this.freq==newNode.freq) {
return 0;
}else if(this.freq<newNode.freq){
return -1;
}else {
return 1;
}
}
}
3.书中HUFFMAN(C)的实现:使用PriorityQueue最小优先队列实现
//1.得到最终的二叉树后,就可以进行编码了,依次遍历二叉树的每一条路径,取每个节点的sign值,
//2.遍历到叶结点后,叶结点charValue值所对应的的路径去除第一个字符即为该字符的编码
//3.例如假如第一个叶结点对应的字符为b,对应的路径为00000,去除第一个字符后,可得最终编码为0000
HuffMan.java
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.PriorityQueue;
public class HuffMan {
public static void main(String[] args){
CharNode[] C = {new CharNode('a', 45),
new CharNode('b', 13),
new CharNode('c', 12),
new CharNode('d', 16),
new CharNode('e', 9),
new CharNode('f', 5)};
for(CharNode c:C) {
System.out.println(c.toString());
}
//获取huffman树的根节点
Node root = Huffman(C);
Map<Character, String> map = new HashMap<Character,String>();
findPath(root, map, new StringBuilder());
System.out.println("字符编码信息为:");
PrintCharEncoderList(map);
}
//构建Huffman树的方法,返回huffman树的根节点
public static Node Huffman(CharNode[] CSet) {
int n = CSet.length;
Node[] huffmanNodeArray = new Node[n];
for(int i=0;i<n;i++) {
huffmanNodeArray[i] = new Node(CSet[i]);
}
PriorityQueue<Node> Q = new PriorityQueue<Node>(n);
for(int i=0;i<n;i++) {
Q.add(huffmanNodeArray[i]);
}
for(int i=0;i<n-1;i++) {
Node z = new Node();
Node x = Q.poll();
x.setSign(0);//因为x是左节点,所以x的sign信号值是0
z.setLeft(x);
Node y = Q.poll();
y.setSign(1);//因为y是右节点,所以y的sign信号值是1
z.setRight(y);
z.setFreq(x.getFreq()+y.getFreq());
Q.add(z);
}
return Q.poll();
}
//1.得到最终的二叉树后,就可以进行编码了,依次遍历二叉树的每一条路径,取每个节点的sign值,
//2.遍历到叶结点后,叶结点charValue值所对应的的路径去除第一个字符即为该字符的编码
//3.例如假如第一个叶结点对应的字符为b,对应的路径为00000,去除第一个字符后,可得最终编码为0000
//遍历获取每个字符的编码值
public static void findPath(Node root, Map<Character,String> map, StringBuilder path) {
//path是记录了路径,每插入一个结点的Sign值后,删除path中最后一个值,map中存放每个字符对应的编码值
if (root.getLeft()== null && root.getRight() == null) {
path.append(root.getSign());
map.put(root.getCharValue(),path.substring(1));//
path.deleteCharAt(path.length() - 1);
return;
}
path.append(root.getSign());
if (root.getLeft() != null) findPath(root.getLeft(), map, path);
if (root.getRight() != null) findPath(root.getRight(), map, path);
path.deleteCharAt(path.length() - 1);
}
//打印编码的信息
public static void PrintCharEncoderList(Map<Character,String> map) {
Character key = null;
String value = null;
Iterator it = map.entrySet().iterator();
while(it.hasNext()) {
Map.Entry<Character,String> entry = (Entry) it.next();
key = entry.getKey();
value = entry.getValue();
System.out.println("字符:"+key+",编码:"+value);
}
}
}
书中例子:
对应的赫夫曼树:
代码结果: