哈夫曼编码是一种基于字符出现频率的最优前缀编码方式,广泛应用于数据压缩领域。下面我将给出一个简单的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);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.

注意上述代码未包含优先队列PriorityQueue<T>的完整实现,您需要自行补充或使用现有的.NET库实现。在实际应用中,为了便于存储和传输,压缩后的比特流通常会转化为二进制或Base64格式。