排序输入的高效霍夫曼编码 示例图
建议先阅读下面的文章:
c语言:c语言 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)_霍夫曼的贪婪c语言-CSDN博客
c++:c++ 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)_霍夫曼的贪婪算法设计核心代码-CSDN博客
c#:C# 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)-CSDN博客
c++ STL:c++ STL 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)-CSDN博客
java:java 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)-CSDN博客
python:python 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)-CSDN博客
javascript:JavaScript 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)-CSDN博客
上面讨论的算法的时间复杂度是 O(nLogn)。如果我们知道给定的数组是排好序的(按频率非递减顺序),我们可以在 O(n) 时间内生成霍夫曼码。以下是针对已排序输入的 O(n) 算法。
1.创建两个空队列。
2.为每个唯一字符创建一个叶节点,并按频率非递减顺序将其入队到第一个队列。最初第二个队列是空的。
3.通过检查两个队列的前面,使两个频率最小的节点出队。重复以下步骤两次
1. 如果第二个队列为空,则从第一个队列出队。
2. 如果第一个队列为空,则从第二个队列出队。
3. 否则,比较两个队列的前面,并使最小的节点出队。
4.创建一个新的内部节点,其频率等于两个节点频率之和。将第一个出队节点设为其左子节点,将第二个出队节点设为右子节点。将此节点入队到第二个队列。
5.重复步骤 3 和 4,直到队列中有多个节点。剩下的节点就是根节点,树就完成了。
示例代码:
// Clean c++ stl code to generate huffman codes if the array
// is sorted in non-decreasing order
#include <bits/stdc++.h>
using namespace std;
// Node structure for creating a binary tree
struct Node {
char ch;
int freq;
Node* left;
Node* right;
Node(char c, int f, Node* l = nullptr,
Node* r = nullptr)
: ch(c)
, freq(f)
, left(l)
, right(r){};
};
// Find the min freq node between q1 and q2
Node* minNode(queue<Node*>& q1, queue<Node*>& q2)
{
Node* temp;
if (q1.empty()) {
temp = q2.front();
q2.pop();
return temp;
}
if (q2.empty()) {
temp = q1.front();
q1.pop();
return temp;
}
if (q1.front()->freq < q2.front()->freq) {
temp = q1.front();
q1.pop();
return temp;
}
else {
temp = q2.front();
q2.pop();
return temp;
}
}
// Function to print the generated huffman codes
void printHuffmanCodes(Node* root, string str = "")
{
if (!root)
return;
if (root->ch != '$') {
cout << root->ch << ": " << str << '\n';
return;
}
printHuffmanCodes(root->left, str + "0");
printHuffmanCodes(root->right, str + "1");
return;
}
// Function to generate huffman codes
void generateHuffmanCode(vector<pair<char, int> > v)
{
if (!v.size())
return;
queue<Node*> q1;
queue<Node*> q2;
for (auto it = v.begin(); it != v.end(); ++it)
q1.push(new Node(it->first, it->second));
while (!q1.empty() or q2.size() > 1) {
Node* l = minNode(q1, q2);
Node* r = minNode(q1, q2);
Node* node = new Node('$', l->freq + r->freq, l, r);
q2.push(node);
}
printHuffmanCodes(q2.front());
return;
}
int main()
{
vector<pair<char, int> > v
= { { 'a' , 5 }, { 'b' , 9 }, { 'c' , 12 },
{ 'd' , 13 }, { 'e' , 16 }, { 'f' , 45 } };
generateHuffmanCode(v);
return 0;
}
输出:
f: 0
c: 100
d: 101
a: 1100
b: 1101
e: 111
时间复杂度: O(n)
如果输入未排序,则需要先对其进行排序,然后才能通过上述算法进行处理。排序可以使用堆排序或合并排序来完成,两者都在 Theta(nlogn) 中运行。因此,对于未排序的输入,总体时间复杂度变为 O(nlogn)。
辅助空间: O(n)