/** * Introduction to Algorithms, Second Edition * 16.3 Huffman codes * * @author 土豆爸爸 * */ import java.util.List; public class Huffman { static class Node implements IPriorityQueueElement<Integer>{ Node left; //左子节点 Node right; //右子节点 Integer f; //频率 char c; //字符 public Node() {} public Node(char c, Integer f) { this.c = c; this.f = f; } public Integer getKey() { return f; } } public static Node encode(List<Node> nodes) { int n = nodes.size(); //根据频率生成最小优先队列 MinPriorityQueue<Integer, Node> queue = new MinPriorityQueue<Integer, Node>(n); for(Node node : nodes) { queue.insert(node); } for(int i = 0; i < n - 1; i++) { Node node = new Node(); Node x = queue.extractMin(); //取出队列的前两个元素 Node y = queue.extractMin(); node.left = x; //将取出两个元素作为新节点的子节点 node.right = y; node.f = x.f + y.f; //新节点的频率是子节点频率之和 queue.insert(node); //插入到队列中 } return queue.extractMin(); } } /** * Introduction to Algorithms, Second Edition * 6.5 min-priority queue * * @author 土豆爸爸 * */ import java.util.EmptyStackException; public class MinPriorityQueue<KeyType extends Comparable<KeyType>, T extends IPriorityQueueElement<KeyType>> { T[] array; int heapSize; /** * 构造函数 * @param size 初始数组大小 */ @SuppressWarnings("unchecked") public MinPriorityQueue(int size) { array = (T[]) new IPriorityQueueElement[size]; } /** * 获取当前heap中的最小值 * * @return 最小值 */ public T minimum() { return array[0]; } /** * 获取当前heap中的最小值,并从heap中删除最小值 * @return 最小值 */ public T extractMin() { if (heapSize < 1) { throw new EmptyStackException(); } T min = array[0]; array[0] = array[heapSize - 1]; heapSize--; minHeapify(0); return min; } /** * 插入一个元素 * @param e */ @SuppressWarnings("unchecked") public void insert(T e) { if (heapSize == array.length) { T[] newArray = (T[]) new IPriorityQueueElement[array.length * 2]; System.arraycopy(array, 0, newArray, 0, array.length); array = newArray; } int i = heapSize++; array[i] = e; int p = parent(i); // 父结点索引 while (i > 0 && array[p].getKey().compareTo(array[i].getKey()) > 0) { T temp = array[i]; array[i] = array[p]; array[p] = temp; i = p; p = parent(i); } } /** * 使数组的第i个元素按max heap规则重排 * * @param i * 元素索引 */ private void minHeapify(int i) { int l = left(i); int r = right(i); int smallest; // 当前结点/左子结点/右子结点中最大值的索引 if (l < heapSize && array[l].getKey().compareTo(array[i].getKey()) < 0) { smallest = l; } else { smallest = i; } if (r < heapSize && array[r].getKey().compareTo(array[smallest].getKey()) < 0) { smallest = r; } if (smallest != i) { // 如果最大值不是当前结点,进行交换 T temp = array[i]; array[i] = array[smallest]; array[smallest] = temp; // 递归调用,直到当前结点比其子结点大 minHeapify(smallest); } } /** * 计算结点索引为i的元素的父结点的索引 * * @param i * 当前索引 * @return 父结点的索引 */ private int parent(int i) { return (i + 1) / 2 - 1; } /** * 计算结点索引为i的元素的左子结点的索引 * * @param i * 当前索引 * @return 左子结点的索引 */ private int left(int i) { return 2 * i + 1; } /** * 计算结点索引为i的元素的右子结点的索引 * * @param i * 当前索引 * @return 右子结点的索引 */ private int right(int i) { return 2 * i + 2; } } public interface IPriorityQueueElement<KeyType extends Comparable<KeyType>>{ KeyType getKey(); } import java.util.ArrayList; import java.util.List; import junit.framework.TestCase; public class HuffmanTest extends TestCase { public void testEncode() { List<Huffman.Node> c = new ArrayList<Huffman.Node>(); c.add(new Huffman.Node('a', 45)); c.add(new Huffman.Node('b', 13)); c.add(new Huffman.Node('c', 12)); c.add(new Huffman.Node('d', 16)); c.add(new Huffman.Node('e', 9)); c.add(new Huffman.Node('f', 5)); Huffman.Node root = Huffman.encode(c); assertEquals(100, root.f.intValue()); assertEquals(45, root.left.f.intValue()); assertEquals('a', root.left.c); assertEquals(55, root.right.f.intValue()); assertEquals('c', root.right.left.left.c); assertEquals('b', root.right.left.right.c); assertEquals('f', root.right.right.left.left.c); assertEquals('e', root.right.right.left.right.c); assertEquals('d', root.right.right.right.c); } }
算法导论示例-Huffman
最新推荐文章于 2017-06-09 11:36:12 发布