Mind and Hand Help

Huffman Tree

哈夫曼树的定义

操作定义

interface HuffmanTree { fun isEmpty(): Boolean = size() == 0 fun size(): Int /** * 获取根节点 */ fun getRoot(): HNode? /** * weighted path length */ fun wpl(): Int /** * 获取编码表 */ fun getEncodingTable(): Map<Char, String> fun printEncodingTable() fun printTree() }

节点定义

/** * 哈夫曼树的节点 */ data class HNode( val data: Char, val weight: Int, val depth: Int = 0, val left: HNode? = null, val right: HNode? = null ) { fun isLeaf(): Boolean = left == null && right == null } internal fun HNode.merge(node: HNode): HNode { return HNode( data = '?', weight = this.weight + node.weight, left = if (this.weight <= node.weight) this else node, right = if (this.weight > node.weight) this else node ) }

哈夫曼树的实现

internal class HuffmanTreeImpl : HuffmanTree { private var root: HNode? = null private var size: Int = 0 private val encodingTable: MutableMap<Char, String> = mutableMapOf() constructor(charCountMap: Map<Char, Int>) { this.root = this.buildTree(charCountMap) this.buildEncodingTable(this.root) } override fun size() = this.size /** * 不针对 size=0 或者 size = 1 的进行构建 */ private fun buildTree(charCountMap: Map<Char, Int>): HNode? { if (charCountMap.size <= 1) { println("Huffman Tree cannot be built with less than 2 characters.") return null } this.size = charCountMap.size val heap: Heap<HNode> = HeapImpl(HeapType.MIN_HEAP, Comparator.comparing { it.weight }) charCountMap.forEach { (c, count) -> heap.add(HNode(data = c, weight = count)) } while (heap.size() > 1) { val min = heap.extract() val secondMin = heap.extract() heap.add(min!!.merge(secondMin!!)) } return heap.extract() } override fun getRoot(): HNode? = root override fun wpl(): Int { return 0 } override fun getEncodingTable(): Map<Char, String> = encodingTable /** * 构建编码表 * */ private fun buildEncodingTable(root: HNode?) { if (root == null) { return } this.dfsBuildEncodingTable(root, "0") } /** * 向左为0 向右为1 */ private fun dfsBuildEncodingTable(node: HNode, current: String) { if (node.isLeaf()) { encodingTable[node.data] = current } node.left?.let { dfsBuildEncodingTable(it, current + "0") } node.right?.let { dfsBuildEncodingTable(it, current + "1") } } override fun printEncodingTable() { println("Encoding Table:") encodingTable.forEach { (c, s) -> println("'$c':$s") } } override fun printTree() { val r = this.root if (r == null) { println("Empty Tree") return } // 根节点不加连接符 println(nodeLabel(r)) // 递归打印左右子树 printTree(r.left, prefix = "", isLeft = true) printTree(r.right, prefix = "", isLeft = false) } private fun printTree(node: HNode?, prefix: String, isLeft: Boolean) { if (node == null) return val branch = if (isLeft) "├── " else "└── " println(prefix + branch + nodeLabel(node)) val childPrefix = prefix + if (isLeft) "│ " else " " printTree(node.left, childPrefix, true) printTree(node.right, childPrefix, false) } private fun nodeLabel(n: HNode): String { return if (n.isLeaf()) "'${n.data}':${n.weight}" else "*:${n.weight}" } }
27 January 2026