用C语言编写程序。基于哈夫曼树的数据压缩算法 描述:输入一串字符串,根据给定的字符串中字符出现的频率建立相应哈夫曼树,构造哈夫曼编码表,在此基础上可以对待压缩文件进行压缩(即编码),同时可以对压缩后的二进制编码文件进行解压(即译码)。 输入:多组数据,每组数据一行,为一个字符串(只考虑26个小写字母即可)。当输入字符串为“0”时,输入结束。 输出:每组数据输出2n+4行(n为输入串中字符类别的个数)。第一行为统计出来的字符出现频率(只输出存在的字符,格式为:字符:频度),每两组字符之间用一个空格分隔,字符按照ASCII码从小到大的顺序排列。第二行至第2n行为哈夫曼树的存储结构的终态(形如教材139页表5.2(b),一行当中的数据用空格分隔)。第2n+2行为每个字符的哈夫曼编码(只输出存在的字符,格式为:字符:编码),每两组字符之间用一个空格分隔,字符按照ASCII码从小到大的顺序排列。第2n+3行为编码后的字符串,第2n+4行为解码后的字符串(与输入的字符串相同)。
时间: 2023-06-18 17:05:31 浏览: 150
优化哈夫曼编码数据压缩技术及程序实现 (1995年)
以下为C语言代码实现:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_CHAR_NUM 26 // 最多只考虑26个小写字母
#define MAX_TREE_NODE_NUM (2 * MAX_CHAR_NUM - 1)
#define MAX_CODE_LENGTH 20
typedef struct TreeNode {
int weight;
int parent;
int left_child;
int right_child;
} TreeNode;
typedef struct Code {
char ch;
char code[MAX_CODE_LENGTH + 1];
} Code;
int get_freq(char *str, int freq[]) {
int len = strlen(str);
int i, idx, cnt = 0;
for (i = 0; i < len; i++) {
idx = str[i] - 'a';
if (freq[idx] == 0) cnt++;
freq[idx]++;
}
return cnt;
}
void init_tree(TreeNode *tree, int n) {
int i;
for (i = 0; i < n; i++) {
tree[i].weight = 0;
tree[i].parent = -1;
tree[i].left_child = -1;
tree[i].right_child = -1;
}
}
void build_tree(TreeNode *tree, int freq[], int n) {
int i, j, idx1, idx2, min1, min2;
for (i = 0; i < n - 1; i++) {
min1 = min2 = 0x7fffffff;
idx1 = idx2 = -1;
for (j = 0; j < n + i; j++) {
if (tree[j].parent == -1) {
if (tree[j].weight < min1) {
min2 = min1;
idx2 = idx1;
min1 = tree[j].weight;
idx1 = j;
} else if (tree[j].weight < min2) {
min2 = tree[j].weight;
idx2 = j;
}
}
}
tree[idx1].parent = n + i;
tree[idx2].parent = n + i;
tree[n + i].weight = min1 + min2;
tree[n + i].left_child = idx1;
tree[n + i].right_child = idx2;
}
}
void get_code(TreeNode *tree, Code code[], int n) {
int i, j, p, k;
char tmp[MAX_CODE_LENGTH + 1];
for (i = 0; i < n; i++) {
p = i;
k = 0;
while (tree[p].parent != -1) {
if (tree[tree[p].parent].left_child == p) {
tmp[k++] = '0';
} else {
tmp[k++] = '1';
}
p = tree[p].parent;
}
tmp[k] = '\0';
code[i].ch = i + 'a';
for (j = 0; j < k; j++) {
code[i].code[k - 1 - j] = tmp[j];
}
code[i].code[k] = '\0';
}
}
void encode(char *str, Code code[], int n, char *enc_str) {
int len = strlen(str);
int i, j, idx;
char *p = enc_str;
for (i = 0; i < len; i++) {
idx = str[i] - 'a';
for (j = 0; j < strlen(code[idx].code); j++) {
*p++ = code[idx].code[j];
}
}
*p = '\0';
}
void decode(char *enc_str, TreeNode *tree, int n, char *dec_str) {
int len = strlen(enc_str);
int i, p = 0;
for (i = 0; i < len; i++) {
if (enc_str[i] == '0') {
p = tree[p].left_child;
} else {
p = tree[p].right_child;
}
if (tree[p].left_child == -1 && tree[p].right_child == -1) {
*dec_str++ = p + 'a';
p = 0;
}
}
*dec_str = '\0';
}
int main() {
char str[1001], enc_str[1001], dec_str[1001];
int freq[MAX_CHAR_NUM];
TreeNode tree[MAX_TREE_NODE_NUM];
Code code[MAX_CHAR_NUM];
int n, i, j;
while (1) {
scanf("%s", str);
if (strcmp(str, "0") == 0) break;
n = get_freq(str, freq);
init_tree(tree, 2 * n - 1);
for (i = 0; i < n; i++) {
tree[i].weight = freq[i];
}
build_tree(tree, freq, n);
get_code(tree, code, n);
// 输出字符出现频率
for (i = 0; i < n; i++) {
if (freq[i] > 0) {
printf("%c:%d ", i + 'a', freq[i]);
}
}
printf("\n");
// 输出哈夫曼树的存储结构
for (i = 0; i < 2 * n - 1; i++) {
printf("%d %d %d %d\n", tree[i].weight, tree[i].parent, tree[i].left_child, tree[i].right_child);
}
// 输出编码
for (i = 0; i < n; i++) {
if (strlen(code[i].code) > 0) {
printf("%c:%s ", code[i].ch, code[i].code);
}
}
printf("\n");
// 对字符串进行编码
encode(str, code, n, enc_str);
printf("%s\n", enc_str);
// 对编码进行解码
decode(enc_str, tree, n, dec_str);
printf("%s\n", dec_str);
}
return 0;
}
```
阅读全文