package cn.zhf.test;
import java.util.Comparator;
import java.util.NoSuchElementException;
public class HuffmanTree {
final int SIZE = 256;
public static void main(String[] args) {
new HuffmanTree().encode();
}
// 编码
public void encode() {
String str = "hello";
char[] ch = str.toCharArray();
int[] freq = new int[SIZE];
// 字符频率统计
for (int i = 0; i < ch.length; i++)
freq[ch[i]]++;
Node1 root = buildTrie(freq);
Node1.printTree(root);
printBinaryTree(root, 0);
}
// 打印树形二叉树
public static void printBinaryTree(Node1 root, int level) {
if (root == null)
return;
printBinaryTree(root.right, level + 1);
if (level != 0) {
for (int i = 0; i < level - 1; i++)
System.out.print("|\t");
System.out.println("|-------" + root.ch + ":" + root.freq);
} else
System.out.println(root.ch + ":" + root.freq);
printBinaryTree(root.left, level + 1);
}
/**
* 创建哈夫曼树 1.根据频率表,将所有字符按照频率从小到大的顺序插入优先级队列中
* 2.从优先级队列的第一个节点开始,把优先级最低的2个节点左右接到一个新的节点下,两者频率之和作为新节点的频率, 然后把这个新节点插入到优先级队列中
* 3.循环上述过程直到优先级队列只剩下一个根节点,此时哈夫曼树构造完成。
*/
public Node1 buildTrie(int[] freq) {
PQueue pq = new PQueue(freq.length);
for (int i = 0; i < freq.length; i++)
if (freq[i] > 0)
pq.insert(new Node1((char) i, freq[i], null, null));
while (pq.size() > 1) {
Node1 left = pq.delMin();
Node1 right = pq.delMin();
Node1 parent = new Node1('\0', left.freq + right.freq, left, right);
pq.insert(parent);
}
return pq.delMin();
}
}
// 节点类
class Node1 {
char ch;
int freq;
Node1 left, right;
public Node1(char ch, int freq, Node1 left, Node1 right) {
this.ch = ch;
this.freq = freq;
this.left = left;
this.right = right;
}
// 判断是否是叶节点
public boolean isLeaf() {
return left == null && right == null;
}
// 节点频率比较
public int compareTo(Node1 that) {
return this.freq - that.freq;
}
public String toString() {
return "ch:" + this.ch + "; freq:" + this.freq;
}
/**
* 编码: 从根节点开始,向左的方向上标记为0,向右的方向上标记为1
*/
private void printNode(String path) {
if ((left == null) && (right == null))
System.out.println(ch + " " + path);
if (left != null)
left.printNode(path + '0');
if (right != null)
right.printNode(path + '1');
}
public static void printTree(Node1 tree) {
tree.printNode("");
}
}
// 优先级队列
class PQueue {
Node1[] node1;
int N;
Comparator comparator;
public PQueue(int size) {
node1 = new Node1[size];
N = 0;
}
public PQueue() {
}
public boolean isEmpty() {
return N == 0;
}
public int size() {
return N;
}
// 插入队列中,新插入的节点先放在队尾
public boolean insert(Node1 node) {
if (node1.length == size())
return false;
node1[++N] = node;
swim(N);
return true;
}
// 新插入的数与其他数比较
private void swim(int k) {
while (k > 1 && greater(k / 2, k)) {
swap(k, k / 2);
k = k / 2;
}
}
// 比较大小
private boolean greater(int i, int j) {
if (comparator == null) {
return ((Comparable) node1[i].freq).compareTo(node1[j].freq) < 0;
} else {
return comparator.compare(node1[i].freq, node1[j].freq) < 0;
}
}
// 交换位置
private void swap(int i, int j) {
Node1 temp = node1[i];
node1[i] = node1[j];
node1[j] = temp;
}
// 返回并移除最小值
public Node1 delMin() {
if (isEmpty())
throw new NoSuchElementException("underflow!");
else
return node1[N--];
}
}
哈夫曼编码
最新推荐文章于 2020-07-28 12:46:53 发布