哈夫曼编码是一种基于字符出现频率的最优前缀编码方式,广泛应用于数据压缩领域。下面我将给出一个简单的C#实现哈夫曼编码(压缩)和解压缩的示例,包括构建哈夫曼树、编码和解码过程:
Csharp
1using System; 2using System.Collections.Generic; 3 4// 定义节点类 5public class Node : IComparable<Node> 6{ 7 public char Value { get; set; } // 节点值,如果是叶子节点则是字符 8 public int Frequency { get; set; } // 字符出现频率 9 public Node Left { get; set; } 10 public Node Right { get; set; } 11 12 public Node(char value, int frequency) 13 { 14 Value = value; 15 Frequency = frequency; 16 } 17 18 public int CompareTo(Node other) 19 { 20 return this.Frequency.CompareTo(other.Frequency); 21 } 22} 23 24public static class HuffmanCoding 25{ 26 // 构建哈夫曼树 27 public static Node BuildHuffmanTree(Dictionary<char, int> frequencies) 28 { 29 var queue = new PriorityQueue<Node>(new List<Node>(frequencies.Select(x => new Node(x.Key, x.Value)))); 30 while (queue.Count > 1) 31 { 32 var left = queue.Dequeue(); 33 var right = queue.Dequeue(); 34 35 var newNode = new Node('\0', left.Frequency + right.Frequency); 36 newNode.Left = left; 37 newNode.Right = right; 38 39 queue.Enqueue(newNode); 40 } 41 return queue.Dequeue(); 42 } 43 44 // 从哈夫曼树生成编码字典 45 public static Dictionary<char, string> GenerateCodes(Node node, string codeSoFar = "", Dictionary<char, string> codes = null) 46 { 47 if (codes == null) codes = new Dictionary<char, string>(); 48 49 if (node.Left == null && node.Right == null) // 叶子节点 50 { 51 codes[node.Value] = codeSoFar; 52 return codes; 53 } 54 55 GenerateCodes(node.Left, codeSoFar + "0", codes); 56 GenerateCodes(node.Right, codeSoFar + "1", codes); 57 58 return codes; 59 } 60 61 // 压缩方法 62 public static string Compress(string input, Dictionary<char, string> huffmanCodes) 63 { 64 var compressedData = new StringBuilder(); 65 foreach (char c in input) 66 { 67 compressedData.Append(huffmanCodes[c]); 68 } 69 return compressedData.ToString(); 70 } 71 72 // 解压缩方法 73 public static string Decompress(string compressedData, Node huffmanTree) 74 { 75 var decompressedData = new StringBuilder(); 76 var currentNode = huffmanTree; 77 foreach (char bit in compressedData) 78 { 79 if (bit == '0') 80 { 81 currentNode = currentNode.Left ?? throw new ArgumentException("Invalid Huffman tree or data"); 82 } 83 else if (bit == '1') 84 { 85 currentNode = currentNode.Right ?? throw new ArgumentException("Invalid Huffman tree or data"); 86 } 87 88 if (currentNode.Left == null && currentNode.Right == null) 89 { 90 decompressedData.Append(currentNode.Value); 91 currentNode = huffmanTree; 92 } 93 } 94 return decompressedData.ToString(); 95 } 96} 97 98// 需要自定义优先队列PriorityQueue,这里仅示意,你可以自己实现或使用.NET中的堆结构 99public class PriorityQueue<T> where T : IComparable<T> 100{ 101 // ... 实现优先队列相关方法 ... 102} 103 104// 使用: 105var frequencies = new Dictionary<char, int>(); 106// 假设已统计好字符串中各字符频率并填充到frequencies中 107var huffmanTree = HuffmanCoding.BuildHuffmanTree(frequencies); 108var huffmanCodes = HuffmanCoding.GenerateCodes(huffmanTree); 109var inputString = "Your input string"; 110var compressed = HuffmanCoding.Compress(inputString, huffmanCodes); 111var decompressed = HuffmanCoding.Decompress(compressed, huffmanTree);
注意上述代码未包含优先队列PriorityQueue<T>的完整实现,您需要自行补充或使用现有的.NET库实现。在实际应用中,为了便于存储和传输,压缩后的比特流通常会转化为二进制或Base64格式。