哈夫曼编码(Huffman Coding),这是一种广泛使用的数据压缩技术。哈夫曼编码通过为常见的数据分配较短的编码,而为不常见的数据分配较长的编码,从而实现有效的数据压缩。
基本代码框架:
-
构建哈夫曼树(Huffman Tree):
- 输入为一系列叶子节点,每个节点有一个权值,通常代表该字符在待编码字符串中出现的频率。
- 程序首先构建一个哈夫曼树。在这个树中,较轻的节点更接近树的根,而较重的节点则更远离根。这样做的结果是最常见的数据(权重最重的节点)有最短的路径,而不常见的数据(权重最轻的节点)有最长的路径。
-
生成哈夫曼编码(Huffman Coding):
- 一旦哈夫曼树被构建,程序就会为每个字符生成一个唯一的二进制编码。
- 这些编码是通过从树的根到每个叶子节点的路径生成的。沿着路径向左移动表示一个“0”,向右移动表示一个“1”。
- 这样,每个叶子节点(代表一个字符)都会有一个对应的唯一的二进制编码。
-
内存管理:
- 程序中使用了动态内存分配(
malloc
)来创建哈夫曼树和存储编码。 - 适当的内存管理确保程序运行时不会出现内存泄露。
- 程序中使用了动态内存分配(
-
用户交互:
- 程序允许用户输入叶子节点的数量和每个节点的权值。
- 然后,它输出每个叶子节点对应的哈夫曼编码。
源代码:
#include<iostream>
#include<cstring>
using namespace std;
// 定义哈夫曼树的结点结构
typedef struct {
int weight; // 结点的权值
int parent, lchild, rchild; // 父节点、左孩子、右孩子的索引
} HTNode, *HufTree;
typedef char** HuffmanCode;
// 选择两个权值最小且未被选中的结点
void Select(HufTree HT, int i, int &s1, int &s2) {
int j;
int mindex1 = 0, mindex2 = 0;
HT[0].weight = 999;
for (j = 1; j <= i - 1; j++) {
if (HT[j].parent == 0) {
if (HT[mindex1].weight > HT[j].weight) {
mindex1 = j;
}
}
}
for (j = 1; j <= i - 1; j++) {
if (HT[j].parent == 0 && j != mindex1) {
if (mindex2 == 0 || HT[mindex2].weight > HT[j].weight) {
mindex2 = j;
}
}
}
s1 = mindex1;
s2 = mindex2;
}
// 构建哈夫曼树并生成哈夫曼编码
void HufCode(int n, int* w, HufTree &HT, HuffmanCode &HC) {
int m, i;
int s1, s2, start, c, f;
char* cd;
HufTree p;
if (n <= 1) {
return;
}
m = 2 * n - 1;
HT = (HufTree)malloc((m+1) * sizeof(HTNode));
if (HT == NULL) {
cout << "空间分配失败";
exit(0);
}
for (i = 1; i <= n; i++) {
HT[i].weight = w[i-1];
HT[i].lchild = 0;
HT[i].rchild = 0;
HT[i].parent = 0;
}
for (; i <= m; i++) {
HT[i].weight = 0;
HT[i].parent = 0;
HT[i].lchild = 0;
HT[i].rchild = 0;
}
for (i = n + 1; i <= m; i++) {
Select(HT, i, s1, s2);
HT[s1].parent = i;
HT[s2].parent = i;
HT[i].lchild = s1;
HT[i].rchild = s2;
HT[i].weight = HT[s1].weight + HT[s2].weight;
}
HC = (HuffmanCode)malloc((n + 1) * sizeof(char*));
if (HC == NULL) {
cout << "空间分配失败";
exit(0);
}
cd = (char*)malloc(n * sizeof(char));
if (cd == NULL) {
cout << "空间分配失败";
exit(0);
}
cd[n - 1] = '\0';
for (i = 1; i <= n; i++) {
start = n - 1;
for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent) {
if (HT[f].lchild == c) {
cd[--start] = '0';
} else {
cd[--start] = '1';
}
}
HC[i] = (char*)malloc((n - start) * sizeof(char));
if (HC[i] == NULL) {
cout << "空间分配失败";
exit(0);
}
strcpy(HC[i], &cd[start]);
}
free(cd);
}
int main() {
int n, i;
int w[100];
HuffmanCode HC;
HufTree HT;
cout << "请输入叶子节点数:";
cin >> n;
cout << "请依次输入各个结点权值(空格隔开):";
for (i = 0; i < n; i++) {
cin >> w[i];
}
if (n == 1) {
cout << "只有一个结点,其编码为:0" << endl;
return 0;
}
else if (n > 1) {
HufCode(n, w, HT, HC);
for (i = 1; i <= n; i++) {
cout << "第" << i << "个结点哈夫曼编码为:" << HC[i] << endl;
}
return 0;
}
}
运行结果