1、问题
参考我的博客:贪心算法之哈夫曼编码问题
2、优先队列知识复习
参考我的博客:
C++之STL之priority_queue
3、代码实现
#include <iostream>
#include <queue>
using namespace std;
//最大字符编码数组长度
#define MAXCODELEN 100
//最大哈夫曼节点结构体数组个数
#define MAXHAFF 100
//最大哈夫曼编码结构体数组的个数
#define MAXCODE 100
#define MAXWEIGHT 10000;
typedef struct Haffman
{
//权重
int weight;
//字符
char ch;
//父节点
int parent;
//左儿子节点
int leftChild;
//右儿子节点
int rightChild;
//下标
int index;
}HaffmaNode;
struct cmp
{
bool operator() (HaffmaNode haffman1, HaffmaNode haffman2)
{
return haffman1.weight > haffman2.weight;
}
};
typedef struct Code
{
//字符的哈夫曼编码的存储
int code[MAXCODELEN];
//从哪个位置开始
int start;
}HaffmaCode;
HaffmaNode haffman[MAXHAFF];
HaffmaCode code[MAXCODE];
priority_queue<HaffmaNode, vector<HaffmaNode>, cmp> que;
void buildHaffman(int all)
{
//哈夫曼节点的初始化之前的工作, weight为0,parent,leftChile,rightChile都为-1
for (int i = 0; i < all * 2 - 1; ++i)
{
haffman[i].weight = 0;
haffman[i].parent = -1;
haffman[i].leftChild = -1;
haffman[i].rightChild = -1;
haffman[i].index = -1;
}
std::cout << "请输入需要哈夫曼编码的字符和权重大小" << std::endl;
for (int i = 0; i < all; i++)
{
std::cout << "请分别输入第个" << i << "哈夫曼字符和权重" << std::endl;
std::cin >> haffman[i].ch;
std::cin >> haffman[i].weight;
haffman[i].index = i;
que.push(haffman[i]);
}
/**
while (!que.empty())
{
HaffmaNode node = que.top();
std::cout << node.weight << std::endl;
que.pop();
}
**/
for (int i = 0; i < all - 1; ++i)
{
HaffmaNode node1, node2;
node1 = que.top();
std::cout << node1.weight << std::endl;
que.pop();
node2 = que.top();
std::cout << node2.weight << std::endl;
que.pop();
haffman[all + i].weight = node1.weight + node2.weight;
haffman[all + i].leftChild = node1.index;
haffman[all + i].rightChild = node2.index;
haffman[all + i].index = all + i;
//这里不是node1.parent = all + i和node2.parent = all + i;
//不然临时变量销毁了
//node1.parent = all + i;
//node2.parent = all + i;
haffman[node1.index].parent = all + i;
haffman[node2.index].parent = all + i;
std::cout << "haffman["<<all + i << "]:" << haffman[all + i].weight << "left is:" << haffman[all + i].leftChild << "right is:" << haffman[all + i].rightChild << std::endl;
que.push(haffman[all + i]);
}
}
//打印每个字符的哈夫曼编码
void printCode(int all)
{
//保存当前叶子节点的字符编码
HaffmaCode hCode;
//当前父节点
int curParent;
//下标和叶子节点的编号
int c;
//遍历的总次数
for (int i = 0; i < all; ++i)
{
hCode.start = all - 1;
c = i;
curParent = haffman[i].parent;
//遍历的条件是父节点不等于-1
while (curParent != -1)
{
//我们先拿到父节点,然后判断左节点是否为当前值,如果是取节点0
//否则取节点1,这里的c会变动,所以不要用i表示,我们用c保存当前变量i
if (haffman[curParent].leftChild == c)
{
hCode.code[hCode.start] = 0;
std::cout << "hCode.code[" << hCode.start << "] = 0" << std::endl;
}
else
{
hCode.code[hCode.start] = 1;
std::cout << "hCode.code[" << hCode.start << "] = 1" << std::endl;
}
hCode.start--;
c = curParent;
curParent = haffman[c].parent;
}
//把当前的叶子节点信息保存到编码结构体里面
for (int j = hCode.start + 1; j < all; ++j)
{
code[i].code[j] = hCode.code[j];
}
code[i].start = hCode.start;
}
}
int main()
{
std::cout << "请输入有多少个哈夫曼字符" << std::endl;
int all = 0;
std::cin >> all;
if (all <= 0)
{
std::cout << "您输入的个数有误" << std::endl;
return -1;
}
buildHaffman(all);
printCode(all);
for (int i = 0; i < all * 2 - 1; ++i)
{
std::cout << haffman[i].parent << std::endl;
}
for (int i = 0; i < all; ++i)
{
std::cout << haffman[i].ch << ": Haffman Code is:";
for (int j = code[i].start + 1; j < all; ++j)
{
std::cout << code[i].code[j];
}
std::cout << std::endl;
}
return 0;
}
4、运行结果
请输入有多少个哈夫曼字符
6
请输入需要哈夫曼编码的字符和权重大小
请分别输入第个0哈夫曼字符和权重
a 5
请分别输入第个1哈夫曼字符和权重
b 32
请分别输入第个2哈夫曼字符和权重
c 18
请分别输入第个3哈夫曼字符和权重
d 7
请分别输入第个4哈夫曼字符和权重
e 25
请分别输入第个5哈夫曼字符和权重
f 13
5
7
haffman[6]:12left is:0right is:3
12
13
haffman[7]:25left is:6right is:5
18
25
haffman[8]:43left is:2right is:4
25
32
haffman[9]:57left is:7right is:1
43
57
haffman[10]:100left is:8right is:9
hCode.code[5] = 0
hCode.code[4] = 0
hCode.code[3] = 0
hCode.code[2] = 1
hCode.code[5] = 1
hCode.code[4] = 1
hCode.code[5] = 0
hCode.code[4] = 0
hCode.code[5] = 1
hCode.code[4] = 0
hCode.code[3] = 0
hCode.code[2] = 1
hCode.code[5] = 1
hCode.code[4] = 0
hCode.code[5] = 1
hCode.code[4] = 0
hCode.code[3] = 1
6
9
8
6
8
7
7
9
10
10
-1
a: Haffman Code is:1000
b: Haffman Code is:11
c: Haffman Code is:00
d: Haffman Code is:1001
e: Haffman Code is:01
f: Haffman Code is:101
5、总结
我们知道有限队列找出最小元素时间复杂度是log(n),所以时间复杂度降低了,变成了n * log(n).