哈夫曼编码是一种用于无损数据压缩的熵编码(即编码效率最高)算法。它是一种可变字长编码方式,比起定长编码的ASCII编码来说,哈夫曼编码能节省很多的空间,因为每一个字符出现的频率不是一致的。
哈夫曼编码的基本原理和流程如下:
struct haftree {
double weight;//节点权值
char c;//节点名字
int lchild, rchild, parent;
};
void selcet(struct haftree* array, int x, int* m1, int* m2) {
double min1 = DBL_MAX;
double min2 = DBL_MAX;
for (int i = 1; i <= x; i++) {
if (array[i].weight < min1 && array[i].parent == 0) {//在构建哈夫曼树的过程 //中,我们需要选择权重最小的两个结点进行合并,构建出新的结点。为了避免重复选择已经合并过的结点, //我们需要在选择最小权重结点的时候排除已经合并的结点。因此,需要通过array[i].parent == 0来判 //断结点是否已经是其他结点的子结点,如果是,则不考虑这个结点。
min1 = array[i].weight;
*m1 = i;
}
}
for (int j = 1; j <= x; j++) {
if (array[j].weight < min2 && j != *m1 && array[j].parent == 0) {
min2 = array[j].weight;
*m2 = j;
}
}
}
void createhaftree(struct haftree*array,int n) {
for (int i = n + 1; i <= 2 * n - 1; i++) {
int m1,m2;
Select(array, i - 1, &m1, &m2);
array[i].weight = array[m1].weight + array[m2].weight;
array[i].lchild = m1;
array[i].rchild = m2;
array[m1].parent = i;
array[m2].parent = i;
}
}
void HuffmanCoding(struct haftree* array, int n) {
char cd[n + 1];
int start;
cd[n] = '\0';
for (int i = 1; i <= n; i++) {
start = n;
int c = i;
int f = array[i].parent;
while (f != 0) {
if (array[f].lchild == c)
cd[--start] = '0';
else
cd[--start] = '1';
c = f;
f = array[f].parent;
}
printf("%s\n", &cd[start]);
}
}
解释如下:
void HuffmanCoding(struct haftree* array, int n)
: 这是一个函数定义,函数名为HuffmanCoding
,它接受一个haftree
结构体数组和一个整数n
作为参数。haftree
是一个自定义的数据结构,用于存储哈夫曼树的节点。char cd[n + 1]; int start; cd[n] = '\0';
: 这里定义了一个字符数组cd
,长度为n+1
,并将最后一个元素设为终止符'\0'
。start
是一个整数,用于记录当前编码的起始位置。for (int i = 1; i <= n; i++)
: 这是一个循环,对haftree
数组中的每个元素进行操作。start = n; int c = i; int f = array[i].parent;
: 在每次循环开始时,将start
设为n
,c
设为当前循环的索引i
,f
设为当前元素的父节点。while (f != 0)
: 这是一个循环,用于生成从叶子节点到根节点的哈夫曼编码。if (array[f].lchild == c) cd[--start] = '0'; else cd[--start] = '1';
: 如果当前节点是其父节点的左孩子,则编码为0
,否则编码为1
。c = f; f = array[f].parent;
: 更新当前节点和父节点。printf("%s\n", &cd[start]);
: 打印生成的哈夫曼编码。总的来说,这段代码实现了哈夫曼编码的生成,它从每个叶子节点开始,沿着到根节点的路径生成编码,然后打印出来。
for (int i = 1; i <= n; i++) {
array[i].weight = weights[i - 1];
array[i].c = chars[i - 1];
array[i].parent = 0;
array[i].lchild = 0;
array[i].rchild = 0;
}
// 初始化非叶子节点
for (int i = n + 1; i < 2 * n; i++) {
array[i].weight = 0;
array[i].c = '\0'; // 非叶子节点没有字符
array[i].parent = 0;
array[i].lchild = 0;
array[i].rchild = 0;
}
#include
#include
#include
struct haftree {
double weight;//节点权值
char c;//节点名字
int lchild, rchild, parent;
};
void Select(struct haftree* array, int x, int* m1, int* m2) {
double min1 = DBL_MAX;
double min2 = DBL_MAX;
for (int i = 1; i <= x; i++) {
if (array[i].weight < min1 && array[i].parent == 0) {
min1 = array[i].weight;
*m1 = i;
}
}
for (int j = 1; j <= x; j++) {
if (array[j].weight < min2 && j != *m1 && array[j].parent == 0) {
min2 = array[j].weight;
*m2 = j;
}
}
}
void createhaftree(struct haftree* array, int n) {
for (int i = n + 1; i <= 2 * n - 1; i++) {
int m1, m2;
Select(array, i - 1, &m1, &m2);
array[i].weight = array[m1].weight + array[m2].weight;
array[i].lchild = m1;
array[i].rchild = m2;
array[m1].parent = i;
array[m2].parent = i;
}
}
void HuffmanCoding(struct haftree* array, int n) {
char cd[n + 1];
int start;
cd[n] = '\0';
for (int i = 1; i <= n; i++) {
start = n;
int c = i;
int f = array[i].parent;
while (f != 0) {
if (array[f].lchild == c)
cd[--start] = '0';
else
cd[--start] = '1';
c = f;
f = array[f].parent;
}
printf("%s\n", &cd[start]);
}
}
int main() {
int n = 5; // 假设有5个字符
struct haftree array[2 * n]; // 创建哈夫曼树数组
double weights[] = { 0.1, 0.15, 0.2, 0.25, 0.3 }; // 假设这是每个字符的权重
char chars[] = { 'a', 'b', 'c', 'd', 'e' }; // 这是每个字符
// 初始化叶子节点
for (int i = 1; i <= n; i++) {
array[i].weight = weights[i - 1];
array[i].c = chars[i - 1];
array[i].parent = 0;
array[i].lchild = 0;
array[i].rchild = 0;
}
// 初始化非叶子节点
for (int i = n + 1; i < 2 * n; i++) {
array[i].weight = 0;
array[i].c = '\0'; // 非叶子节点没有字符
array[i].parent = 0;
array[i].lchild = 0;
array[i].rchild = 0;
}
createhaftree(array, n);
HuffmanCoding(array, n);
return 0;
}