您的位置:首页 > 娱乐 > 八卦 > 赫夫曼编码-C语言

赫夫曼编码-C语言

2024/12/22 17:16:21 来源:https://blog.csdn.net/m0_73701759/article/details/140305993  浏览:    关键词:赫夫曼编码-C语言

实现文件中数据的加解密与压缩:将硬盘上的一个文本文件进行加密,比较加密文件和原始文件的大小差别;对加密文件进行解密,比较原始文件和解码文件的内容是否一致。

代码

#include <stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
typedef struct node* LIST;
typedef struct node* TREE;
struct node
{int high; //高位ascllint low; //判断是否是中文,低位int weight;int code_index; //编码指针char code[100]; //编码数组TREE Left;TREE Right;LIST NEXT;
};
void insert(LIST head, LIST tmp);
LIST find_and_insert(LIST head, LIST tmp);
void output(LIST head);
LIST init_LIST(int high, int low, int weight);
TREE tree_node_init(int high, int low, int weight);
TREE build_tree(LIST head);
void print_huffman_pre(TREE Tree, int flag);
void update_tree(TREE Tree);
void save_file(TREE* a, int right, TREE Tree);
void to_free_tree(TREE Tree);
void to_free_list(LIST head);
void coding(TREE Tree);
void decoding();
TREE queue[1000];
int queue_index = 0;
int sum_bit_coding = 0;
int sum_bit_decoding = 0;
char file_in[100] = "D:\\file.txt";
char file_out[100];
void init_main();
void update_file_out(char file_in[])
{int i;for (i = strlen(file_in) - 1; i >= 0; i--)if (file_in[i] == '\\')break;int j;for (j = 0; j <= i; j++)file_out[j] = file_in[j];
}
int main()
{init_main();return 0;
}
void init_main()
{LIST head = init_LIST(0, 0, 0);FILE* P;while (1){printf("为了结果的准确性,请输入GBK格式的txt文件\n");printf("请输入需要执行的文件及路径\n例如\nD:\\file.txt\n");gets(file_in);fopen_s(&P,file_in, "r");if (P == NULL){printf("文件打开失败\n请重新输入\n");continue;}else{printf("打开成功\n");break;}}update_file_out(file_in);int ch;while ((ch = fgetc(P)) != EOF){LIST tmp = init_LIST(ch, -1, 1);if (ch > 128)tmp->low = fgetc(P);insert(head, find_and_insert(head, tmp));}TREE Tree = build_tree(head);coding(Tree);print_huffman_pre(Tree->NEXT, 0);update_tree(Tree);queue_index = 0;print_huffman_pre(Tree->NEXT, 0);decoding();fclose(P);while (1){int flag;printf("请选择操作命令-> \n \t1:统计信息;\n\t2:词频统计;\n\t3:编码详情;\n\t4:文件输出信息;\n\t5:return\n");scanf_s("%d", &flag);switch (flag){case 1:printf("-----------------------------------\n");printf("文件已经保存,共写入%d比特\n", sum_bit_coding);printf("从文件读取%d比特\n", 8 * (Tree->high + Tree->low * 2));printf("压缩率是%.3f\n", 1.0 * sum_bit_coding / 8 / (Tree->high + Tree->low * 2));printf("共写入解码文件%d比特\n", sum_bit_decoding);printf("-----------------------------------\n");break;case 2:output(head);break;case 3:print_huffman_pre(Tree->NEXT, 1);break;case 4:{char coding_file_name[100];strcpy_s(coding_file_name, file_out);strcat_s(coding_file_name, "coding.txt");char encoding_file_name[100];strcpy_s(encoding_file_name, file_out);strcat_s(encoding_file_name, "encoding.txt");printf("输入文件的路径为%s\n", file_in);printf("加密文件的路径为%s\n", coding_file_name);printf("解码文件的路径为%s\n", encoding_file_name);break;}case 5:return;}}to_free_tree(Tree);to_free_list(head);
}
void decoding()
{sum_bit_decoding = 0;char coding_file_name[100];strcpy_s(coding_file_name, file_out);strcat_s(coding_file_name, "coding.txt");char encoding_file_name[100];strcpy_s(encoding_file_name, file_out);strcat_s(encoding_file_name, "encoding.txt");FILE* in;fopen_s(&in,coding_file_name, "r");FILE* out;fopen_s(&out,encoding_file_name, "wb");int ch;int str_index = 0, left;char str[100];while ((ch = fgetc(in)) != EOF){str[str_index++] = ch;str[str_index] = '\0';for (left = 0; left < queue_index; left++){if (strcmp(queue[left]->code, str) == 0){if (queue[left]->high > 128) sum_bit_decoding += 16;else sum_bit_decoding += 8;if ((char)queue[left]->high == '\n'){fprintf(out, "\r\n");}else{fprintf(out, "%c", queue[left]->high);if (queue[left]->high > 128) fprintf(out, "%c", queue[left]->low);}str_index = 0;break;}}}fclose(in);fclose(out);
}
void to_free_list(LIST head)
{LIST P = head;while (head->NEXT){P = head->NEXT;head->NEXT = head->NEXT->NEXT;free(P);}free(head);
}
void to_free_tree(TREE Tree)
{if (!Tree) return;to_free_tree(Tree->Left);to_free_tree(Tree->Right);free(Tree);
}
void save_file(TREE* a, int right, TREE Tree)
{int left;sum_bit_coding = 0;FILE* P;fopen_s(&P,file_in, "r");char coding_file_name[100];strcpy_s(coding_file_name, file_out);strcat_s(coding_file_name, "coding.txt");FILE* out;fopen_s(&out,coding_file_name, "wb");if (P == NULL)printf("文件打开失败\n");int ch;while ((ch = fgetc(P)) != EOF){LIST tmp = init_LIST(ch, -1, 1);if (ch > 128)tmp->low = fgetc(P);for (left = 0; left < right; left++){if (a[left]->high == tmp->high){if (tmp->high > 128 && tmp->low == a[left]->low){fprintf(out, "%s", a[left]->code);sum_bit_coding += strlen(a[left]->code);}if (tmp->high <= 128){fprintf(out, "%s", a[left]->code);sum_bit_coding += strlen(a[left]->code);}}}free(tmp);}fclose(P);fclose(out);
}
void update_tree(TREE Tree)
{TREE a[1000];int left = 0, right = 0;if (!Tree) return;a[right++] = Tree->NEXT;while (left < right){if (a[left]->Left){a[right++] = a[left]->Left;strcpy_s(a[left]->Left->code, a[left]->code);a[left]->Left->code_index = strlen(a[left]->code);a[left]->Left->code[a[left]->Left->code_index++] = '0';}if (a[left]->Right){a[right++] = a[left]->Right;strcpy_s(a[left]->Right->code, a[left]->code);a[left]->Right->code_index = strlen(a[left]->code);a[left]->Right->code[a[left]->Right->code_index++] = '1';}left++;}save_file(a, right, Tree);
}
TREE tree_node_init(int high, int low, int weight)
{TREE tmp = (TREE)malloc(sizeof(struct node));tmp->high = high;tmp->low = low;tmp->weight = weight;strcpy_s(tmp->code, "\0");tmp->code_index = 0;tmp->Right = NULL;tmp->Left = NULL;tmp->NEXT = NULL;return tmp;
}
TREE build_tree(LIST head)
{TREE Tree = tree_node_init(head->high, head->low, 0);TREE T = Tree;LIST P = head->NEXT;while (P){T->NEXT = tree_node_init(P->high, P->low, P->weight);T = T->NEXT;Tree->weight++;P = P->NEXT;}return Tree;
}
void coding(TREE Tree)
{while (Tree->weight > 1){TREE t1 = Tree->NEXT;Tree->NEXT = Tree->NEXT->NEXT;TREE t2 = Tree->NEXT;Tree->NEXT = Tree->NEXT->NEXT;TREE t = tree_node_init(-1, -1, t1->weight + t2->weight);t->Left = t1;t->Right = t2;insert(Tree, t);Tree->weight--;}
}
void print_huffman_pre(TREE Tree, int flag)
{if (!Tree) return;if ((char)Tree->high == '\n'){queue[queue_index++] = Tree;if (flag)printf("\\n   weight == %d coding = %s\n", Tree->weight, Tree->code);}else if (Tree->high > 128){queue[queue_index++] = Tree;if (flag){putchar(Tree->high);putchar(Tree->low);printf("   weight == %d coding = %s\n", Tree->weight, Tree->code);}}else if (Tree->high != -1){queue[queue_index++] = Tree;if (flag){putchar(Tree->high);printf("   weight == %d coding = %s\n", Tree->weight, Tree->code);}}print_huffman_pre(Tree->Left, flag);print_huffman_pre(Tree->Right, flag);
}
LIST find_and_insert(LIST head, LIST tmp)
{if (tmp->low != -1) head->low++;else head->high++;LIST P = head;while (P->NEXT){if (P->NEXT->high == tmp->high){if (P->NEXT->low != -1 && tmp->low != -1 && P->NEXT->low == tmp->low){LIST found = init_LIST(P->NEXT->high, P->NEXT->low, P->NEXT->weight + 1);LIST del = P->NEXT;P->NEXT = P->NEXT->NEXT;del->NEXT = NULL;free(del);return found;}if (P->NEXT->low == -1 && tmp->low == -1){LIST found = init_LIST(P->NEXT->high, P->NEXT->low, P->NEXT->weight + 1);LIST del = P->NEXT;P->NEXT = P->NEXT->NEXT;del->NEXT = NULL;free(del);return found;}}P = P->NEXT;}return tmp;
}
void insert(LIST head, LIST tmp)
{LIST P = head;while (P->NEXT){if (tmp->weight < P->NEXT->weight)break;P = P->NEXT;}if (!P->NEXT){P->NEXT = tmp;return;}tmp->NEXT = P->NEXT;P->NEXT = tmp;
}
void output(LIST head)
{LIST P = head->NEXT;while (P){if ((char)P->high == '\n'){printf("字符 \\n 个数是%d\t占用字节为%d\t总字节为%d\n", P->weight, P->low == -1 ? 1 : 2, P->weight * (P->low == -1 ? 1 : 2));P = P->NEXT;continue;}printf("字符 ");putchar(P->high);if (P->high > 128)putchar(P->low);printf(" 个数是%d\t占用字节为%d\t总字节为%d\n", P->weight, P->low == -1 ? 1 : 2, P->weight * (P->low == -1 ? 1 : 2));P = P->NEXT;}printf("总字节数为%d\n", head->high + head->low * 2);
}
LIST init_LIST(int high, int low, int weight)
{LIST tmp = (LIST)malloc(sizeof(struct node));tmp->high = high;tmp->low = low;tmp->weight = weight;tmp->NEXT = NULL;return tmp;
}

运行效果

创建文件格式:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OqNAERp5-1720826856997)(https://i-blog.csdnimg.cn/direct/a85d2fb516044620aa0d8273b38737ed.png)]

输入1统计文件信息:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-keSOVIqm-1720826856999)(https://i-blog.csdnimg.cn/direct/d60d534258704ca3a503eaa9ee2d573c.png)]

输入2进行词频统计:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4hhUF46o-1720826857000)(https://i-blog.csdnimg.cn/direct/5397ebd0e8cf4f4991bdf95b6370c66a.png)]

输入3查看编码详情:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zpjukLkB-1720826857000)(https://i-blog.csdnimg.cn/direct/7fe56a66b63848dc949da15b26c27cc9.png)]

输入4文件输出信息:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PzG2J9n4-1720826857001)(https://i-blog.csdnimg.cn/direct/85fb4de64c1e4d9c9dadb1f9a9b703e1.png)]

输入5return:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SkL6rM7B-1720826857001)(https://i-blog.csdnimg.cn/direct/0c680dd78de547c3b62f1d5457c1d68e.png)]

完整步骤:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jdVn5N0V-1720826857002)(https://i-blog.csdnimg.cn/direct/8a7702ee10da4643b12bede5ed97c102.png)]

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com