#include <iostream>
int n=0;
double a[200];
char b[200];
int count=0;
typedef struct{
double weight;
int parent;
int lchild;
int rchild;
char s;
}HTNODE;
typedef HTNODE Huffman[3000];
void InitHT(Huffman T) {
for (int i = 0; i < 2*n-1; i++) {
T[i].rchild = -1;
T[i].lchild = -1;
T[i].parent = -1;
T[i].weight = 10;
}
}
void input(Huffman T)
{
int i = 0;
int flag = 0;
for (int j = 0; j <= 126; j++) {
a[j] = 0;
}
FILE *file = fopen("input.txt", "r");
int ch;
while ((ch = fgetc(file)) != EOF) {
count++;
for (int k = 0; k <= 126; k++) {
if (b[k] == ch) {
flag = 1;
}
}
if (flag == 0) {
n++;
}
for (i = 0; i <= 126; i++) {
if (ch == i) {
a[i]++;
b[i]=ch;
break;
}
}
flag = 0;
}
fclose(file);
}
void set(Huffman T)
{
int y=0;
for(int g=0;g<=126;g++)
{
if(a[g]!=0)
{
T[y].weight=a[g]/count;
T[y].s=b[g];
y++;
}
}
}
int z1;
int z2;
void Selecttwomin(Huffman T,int x,int *m1,int*m2)
{
double min1 =999;
double min2 =999;
int j;
int k;
for(j=0;j<=x;j++)
{
if(T[j].weight<min1 && T[j].parent==-1)
{
min1=T[j].weight;
*m1=j;
z1=*m1;
}
}
// printf("%d\n",z1);
for(k=0;k<=x;k++)
{
if(T[k].weight<min2 &&T[k].parent==-1 && k!=z1)
{
min2=T[k].weight;
*m2=k;
z2=*m2;
}
}
// printf("%dok\n",*m2);
}
void CreatHuffmanTree(Huffman T,int n)
{
int i,m1,m2;
for(i=n;i<2*n-1;i++)
{
Selecttwomin(T,i,&m1,&m2);
T[i].weight=T[z1].weight+T[z2].weight;
T[z1].parent=T[z2].parent=i;
T[i].parent=-1;
T[i].lchild=z1;
T[i].rchild=z2;
}
// printf("%d\n",T[4].lchild);
}
void createcode(Huffman T,int n,char **hc)
{
char * cd =(char*) malloc(n*sizeof(char) );
cd[n-1]='\0';
int now=0;
int i=0;
int p=0;
while(i<n)
{
int start=n;
memset(cd, 0, n); // 清空cd数组
now=i;
p=T[now].parent;
while(p!=-1)
{
start--;
if(now==T[p].lchild)
{
// printf("%d加一啦",now);
cd[start]='1';
} else
{
// printf("%d加0啦",now);
cd[start]='0';
}
now=p;
p=T[p].parent;
// printf("p的值为%d\n",p);
}
hc[i]=(char*)malloc((n-start)*sizeof(char));
strcpy(hc[i],&cd[start]);
// printf("%s",hc[i]);
i++;
}
// printf("%s\n",hc[3]);
}
void printf(Huffman T,char **hc,int index)
{
if(index>=0)
{
if(T[index].lchild==-1&&T[index].rchild==-1)
{
printf("%c:%s\n",T[index].s,hc[index]);
return ;
}
printf(T,hc,T[index].lchild);
printf(T,hc,T[index].rchild);
}
}
void bianma(Huffman T, char **hc)
{
FILE *input = fopen("input.txt", "r");
FILE *output = fopen("compressed.bin", "a"); // 打开文件以追加方式写入
if (input == NULL || output == NULL) {
printf("无法打开文件\n");
return;
}
int ch;
int i=0;
while ((ch = fgetc(input)) != EOF)
{
while(i<n) {
if (ch == T[i].s)
{
fprintf(output,"%s",hc[i]);
}
i++;
// printf("循环一次!\n");
}
i=0;
}
fclose(input);
fclose(output);
}
void yima(Huffman T)
{
FILE *file = fopen("compressed.bin", "r");
FILE *thelast = fopen("thelast.txt", "a"); // 打开文件以追加方式写入
char ch;
int i=2*n-2;
while((ch = fgetc(file)) != EOF)
{
if(ch=='0') {
i = T[i].rchild;
if (T[i].lchild == -1 && T[i].rchild == -1) {
fprintf(thelast,"%c", T[i].s);
i = 2 * n - 2;
}
}
if(ch=='1')
{
i=T[i].lchild;
if(T[i].lchild==-1&&T[i].rchild==-1) {
fprintf(thelast,"%c", T[i].s);
i = 2 * n - 2;
}
}
}
fclose(file);
fclose(thelast);
}
void yasuo()
{
const char *originalFileName = "input.txt";
const char *compressedFileName = "compressed.bin"; // 假设是用二进制格式保存的压缩文件
// 获取原始文件大小
FILE *originalFile = fopen(originalFileName, "rb");
fseek(originalFile, 0, SEEK_END);
long originalSize = ftell(originalFile);
fclose(originalFile);
// 获取压缩后文件大小
FILE *compressedFile = fopen(compressedFileName, "rb");
fseek(compressedFile, 0, SEEK_END);
long compressedSize = ftell(compressedFile)/8;
fclose(compressedFile);
// 计算压缩率
double compressionRatio = 1.0 - ((double)compressedSize / (double)originalSize);
// 将压缩率转化为百分比
double compressionPercentage = compressionRatio * 100.0;
printf("原始文件大小:%ld 字节\n", originalSize);
printf("压缩后文件大小:%ld 字节\n", compressedSize);
printf("压缩率:%.2f%%\n", compressionPercentage);
}
void compare()
{
FILE *file = fopen("input.txt", "r");
FILE *file1 = fopen("thelast.txt", "r");
if (file1 == NULL) {
printf("无法打开文件\n");
return;
}
while(1)
{
char ch = fgetc(file);
char ch1 = fgetc(file1);
// printf("%c",ch);
// printf("%c",ch1);
if(ch!=ch1)
{
printf("我们不一样!");
break;
}
if(ch==EOF && ch1==EOF)
{
printf("其实我们都一样!");
break;
}
}
fclose(file);
fclose(file1);
}
int main() {
Huffman T;
input(T);
InitHT(T);
set(T);
CreatHuffmanTree( T, n);
char *hc[n+1];
createcode(T,n,hc);
printf(T,hc,2*n-2);
bianma(T,hc);
yima(T);
yasuo();
compare();
// FILE *file = fopen("compressed.bin", "w"); // 以写入方式打开文件,将清空文件内容
// if (file == NULL) {
// printf("无法打开文件\n");
// return 1;
// }
// fclose(file); // 立即关闭文件以确保内容被清空
// printf("文件内容已清空\n");
return 0;
}
我是跟着B站上的一个up主写的,有改动。
视频地址如下:数据结构课设之哈夫曼树编码译码代码讲解_哔哩哔哩_bilibili
之前我的实验都是抄的,或者直接让g p t生成,这次算是一个新开始,加油!