/*
霍夫曼编码
哈夫曼树(Huffman Tree),又叫最优二叉树,指的是对于一组具有确定权值的叶子结点的具有最小带权路径长度的二叉树
1.数据移动时无符号不同于有符号,右移要默认为0
2.文件操作以字节为最小单位。凑足写入,最后多一个字节写上次剩余多少
3.区分叶子节点与内部节点,8个字符的最长路径为7
无符号类型的应用,位操作在有符号时候会带符号操作,当系统使用文本方式打开文件后,会对回车做相应处理。文件读取不正确
移位操作时候注意左右不同。当最后一个单元不能完全保存时,最后用一个来存储最后一次操作的位数
k<<=32-count;移位至前面,自底向上寻找编码,但从上到下使用
*/#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<string.h>
#define N 511
#define M 256
typedef struct HTree
{
unsigned char ch;
int parent,lchild,rchild;
unsigned int code;
int codenum;
double weight;
}Tree;
Tree tree[N]={0};
void encode();
void hufftree();
void getcode();
void crackcode();
void printcode();
void translatecode(unsigned char *rdtemp,int filesize);
int main()
{
char ch[3];
while(1)
{
system("cls");
printf(" -----------------------哈夫曼编码解码---------------------\n\n");
printf(" BY:XSY\n\n\n\n");
printf(" 1.哈夫曼编码\n");
printf(" 2.哈夫曼解码\n");
printf(" 3.打印各个字符的哈夫曼编码\n 0.EXIT\n\n");
printf("注:编码文件为test.txt,解码文件名为Htest.txt与源程序放在同一目录\n\n\n ");
gets(ch);
switch(ch[0])
{
case '0': return 0;
case '1':encode();break;
case '2':crackcode();break;
case '3':printcode();break;
}
}
return 0;
}
void encode()
{
FILE *fp;
if((fp=fopen("test.txt","rb"))==NULL)
exit(0);
int All_char[M]={0};
int i;
unsigned char rdtemp[100000];
i=sizeof(unsigned char);
long filesize;
fseek(fp,0,2);
filesize=ftell(fp);
rewind(fp);
fread(rdtemp,filesize,1,fp);
fclose(fp); //读入文本
i=0;
while(i<filesize)
All_char[rdtemp[i++]]++;
for(i=0;i<M;i++)
{
tree[i].ch=i;
tree[i].parent=-1;
tree[i].weight=All_char[i]/(double)filesize;
}
for(i=M;i<N;i++)
tree[i].parent=-1; //统计字符
hufftree(); //create哈夫曼编码
getcode();
//译码写入
translatecode(rdtemp,filesize);
printf("\n\n mission successful! press any key to back...\n");
_getch();
}
void hufftree()
{
int i;
int num1,num2;
int count;
double min1,min2;
int arc;
arc=M;
count=0;
while(arc<N)
{
for(i=0,min1=min2=1.0;i<arc;i++)
{
if(tree[i].parent != -1)
continue;
if(tree[i].weight<min2)
{
if(tree[i].weight<min1)
{
num2=num1;
num1=i;
min2=min1;
min1=tree[i].weight;
}
else
{
num2=i;
min2=tree[i].weight;
}
}
}
tree[arc].lchild=num1;
tree[arc].rchild=num2;
tree[arc].weight=min1+min2;
tree[num1].parent=arc;
tree[num2].parent=arc;
arc++;
}
}
void getcode()
{
int i,j;
int codenum;
int chcount=0;
while(chcount<M)
{
codenum=0;
i=chcount;
while(tree[i].parent != -1)
{
tree[chcount].code>>=1;
codenum++;
j=tree[i].parent;
if(tree[j].rchild == i)
tree[chcount].code |=0x80000000;
i=j;
}
tree[chcount].codenum=codenum;
chcount++;
}
/*
for(i=j=0;i<M;i++)
{
j=tree[i].codenum>j?tree[i].codenum:j;
//printf("%c %d\n",tree[i].ch,tree[i].code);
}*/
}
void translatecode(unsigned char *rdtemp,int filesize)
{
FILE *fp;
int i,j,count;
unsigned int k,l;
if((fp=fopen("Htest.txt","wb"))==NULL)
exit(0);
fwrite(tree,sizeof(Tree),N,fp);
for(i=k=count=0;i<filesize;i++)
{
l=tree[rdtemp[i]].code;
for(j=0;j<tree[rdtemp[i]].codenum;j++,count++)
{
if(count == 32)
{
fwrite(&k,sizeof(int),1,fp);
count=k=0;
}
k<<=1;
if((l&0x80000000) == 0x80000000)
k|=1;
l<<=1;
}
}
k<<=32-count;
if(count)
fwrite(&k,sizeof(int),1,fp);
fwrite(&count,sizeof(int),1,fp);
fclose(fp);
}
void crackcode()
{
int i,j,k;
unsigned int oparrey[500]={0};
FILE *fp;
if((fp=fopen("Htest.txt","r+b"))==NULL)
exit(0);
ftell(fp);
fread(tree,sizeof(Tree),N,fp);
long filesize1,filesize2,filesize;
filesize1=ftell(fp);
fseek(fp,0,2);
filesize2=ftell(fp);
filesize=filesize2-filesize1;
filesize/=4;
fseek(fp,filesize1,0);
fread(oparrey,sizeof(int),filesize,fp);
fclose(fp);
for(i=0,k=N-1;i<filesize-2;i++)
{
for(j=0;j<32;j++)
{
if((oparrey[i]&0x80000000) == 0x80000000)
k=tree[k].rchild;
else
k=tree[k].lchild;
if(tree[k].ch)
{
putchar(tree[k].ch);
k=N-1;
}//字符处理
oparrey[i]<<=1;
}
}
for(j=0;j<(signed)oparrey[filesize-1];j++)
{
if((oparrey[i]&0x80000000) == 0x80000000)
k=tree[k].rchild;
else
k=tree[k].lchild;
if(tree[k].ch)
{
putchar(tree[k].ch);
k=N-1;
}//字符处理
oparrey[i]<<=1;
}
printf("\n\n mission successful! press any key to back...\n");
_getch();
}
void printcode()
{
unsigned int k;
for(int i=0;i<M;i++)
{
k=tree[i].code;
printf("%c\t",tree[i].ch);
for(int j=0;j<tree[i].codenum;j++)
{
if((k&0x80000000) == 0x80000000)
putchar('1');
else
putchar('0');
k<<=1;
}
putchar('\n');
}
printf("\n\n mission successful! press any key to back...\n");
_getch();
}