哈夫曼编码 是一种用于数据压缩的编码方式,它使用变长编码来表示数据源中的符号。频率较高的符号用较短的编码,频率较低的符号用较长的编码 ,从而达到减少总编码长度的目的。
编码过程
例子:
对字母 进行哈夫曼编码时的性质:
1.每个字母对应元素叶节点的值是该字母出现的次数
2.出现次数越多的字符编码越短
3.不出现歧义的情况下编出来的码长度最短
4.编码结果不唯一,字母编出来的码可能不一样,但是长度肯定一样
参考b站视频:哈夫曼树和哈夫曼编码, 看完秒懂!
不会出现歧义原因:不存在任意一个元素节点出现在另一个元素节点的路径中
应用 : 压缩文件
代码实现 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 #include <iostream> #include <queue> #include <unordered_map> #include <string> #include <vector> using namespace std;struct Node { char ch; int freq; Node *left, *right; Node (char ch, int freq) : ch (ch), freq (freq), left (nullptr ), right (nullptr ) {} bool operator <(const Node &node) const { return this ->freq > node.freq; } }; Node* buildHuffmanTree (string text) { unordered_map<char , int > frequency; for (char ch : text) ++frequency[ch]; priority_queue<Node, vector<Node>, greater<Node>> minHeap; for (auto pair : frequency) minHeap.push (*new Node (pair.first, pair.second)); while (minHeap.size () != 1 ) { Node *left = new Node (minHeap.top ()); minHeap.pop (); Node *right = new Node (minHeap.top ()); minHeap.pop (); Node *top = new Node ('\0' , left->freq + right->freq); top->left = left; top->right = right; minHeap.push (*top); } return new Node (minHeap.top ()); } void encodeMap (Node* root, string str, unordered_map<char , string> &huffmanCode) { if (!root) return ; if (!root->left && !root->right) huffmanCode[root->ch] = str; encodeMap (root->left, str + "0" , huffmanCode); encodeMap (root->right, str + "1" , huffmanCode); } void printCodes (unordered_map<char , string> &huffmanCode) { cout << "Character" << "\t" << "Frequency" << "\t" << "Code" << endl; for (auto pair : huffmanCode) cout << pair.first << "\t\t" << huffmanCode[pair.first].size () << "\t\t" << pair.second << endl; } string encode (const string &text, unordered_map<char , string> &huffmanCode) { string encodedString = "" ; for (char ch : text) encodedString += huffmanCode[ch]; return encodedString; } int main () { string text = "this is an example for huffman encoding" ; Node* root = buildHuffmanTree (text); unordered_map<char , string> huffmanCode; encodeMap (root, "" , huffmanCode); printCodes (huffmanCode); string encodedString = encode (text, huffmanCode); cout << "Encoded string: " << encodedString << endl; return 0 ; }
这段代码首先统计了输入字符串中每个字符出现的频率,然后创建了一个最小堆(priority_queue
),其中存储的是由字符及其频率组成的节点。通过不断地从堆中取出两个频率最低的节点并合并成一个新的节点,最终构建出哈夫曼树。之后,通过遍历哈夫曼树生成每个字符对应的编码,并将这些编码存储在一个映射表中。最后,根据这个映射表对原始字符串进行编码。
请注意,这个简单的实现并没有包括解码过程、内存释放或者处理可能的异常情况。在实际应用中,你还需要考虑这些问题。此外,由于C++标准库中没有直接支持优先队列元素为自定义类型的比较,我们重载了小于操作符以适应 priority_queue
的需求。