哈夫曼压缩
Question…
1. Question Analysis
1. 总字母数,哈夫曼编码后各个字母的长度.
2. 进行哈夫曼编码
a. 每一行最少信息(权值、父亲、左孩子、右孩子、代表的字母、待选择叶节点标志flag)--其中有权值没父亲即有flag作用.
b. 找最小两个的下标,产生父子关系,改变各个信息内容.
3. 求各个字母深度
a. 由哈夫曼树性质(前n个为叶子),以及父子关系向上找,直到父亲为0;初始化为1,起传递作用的变量f.
4. 求比值
2. Make it
#include <stdio.h>
#include <string.h>
#define MAX 10001
#define ZMAX 27
typedef struct Node
{
int worth;
int father;
int leftch;
int rich;
int daibiao;
int flag;
}N;
int A[ZMAX];
int B[ZMAX];
char En[MAX];
//char Tmp[10];
N Huf[ZMAX*2];
int getdata()
{
int nos=0; //初始化树
for(int j=0;j<ZMAX*2;j++)
{
Huf[j].father=0;
Huf[j].leftch=0;
Huf[j].daibiao=-1; //用-1好点
Huf[j].rich=0;
Huf[j].worth=0;
Huf[j].flag=0;
}
nos=0; //叶子赋值
for(int i=0;i<ZMAX;i++)
{
if(A[i]!=0)
{
Huf[nos].worth=A[i];
Huf[nos].daibiao=i;
Huf[nos].flag=1; //备选标记
nos++;
}
}
return nos;
}
void getsmall(int no,int &i,int &j) //无脑版找最小两个(前提最多只需要从27个中寻找,时间差异不明显)
{
int ss=-1;
for(int p=0;p<2;p++)
{
for(int k=0;k<no;k++) //初始化
{
if(Huf[k].flag==1)
{
ss=k;
break;
}
}
for(int k=ss+1;k<no;k++)
{
if(Huf[k].flag==0)
{
continue;
}
else
{
if(Huf[k].worth<Huf[ss].worth)
{
ss=k;
}
}
}
Huf[ss].flag=0;
if(p==0)
{
i=ss;
}
else
{
j=ss;
}
}
}
void buildtree(int n)
{
int i,j,no=n;
while(no<=2*n-2)
{
getsmall(no,i,j);
Huf[no].worth=Huf[i].worth+Huf[j].worth;
Huf[no].leftch=i;
Huf[no].rich=j;
Huf[no].flag=1;
Huf[i].father=no;
//Huf[i].flag=0; 在找的时候就置为0
Huf[j].father=no;
//Huf[j].flag=0;
no++;
}
}
//test
/*
void showA()
{
printf("**A[]:\n\n");
for(int i=0;i<ZMAX;i++)
{
printf("A[%d]--%d\n",i,A[i]);
}
}
void showB()
{
printf("**B[]:\n\n");
for(int i=0;i<ZMAX;i++)
{
printf("B[%d]--%d\n",i,B[i]);
}
}
void showHuf(int n)
{
printf("**Huffman Tree:\n\n");
for(int i=0;i<n;i++)
{
printf("*#%d* worth %d --father %d --left %d --right %d --instead %c --flag %d\n",i,Huf[i].worth,Huf[i].father,Huf[i].leftch,Huf[i].rich,Huf[i].daibiao,Huf[i].flag);
}
printf("\n");
}
*/
//testend
int main()
{
int no;
int sum=0;
int besum,afsum;
int deep;
while(1)
{ //接收数据
for(int i=0;i<ZMAX;i++)
{
if(i<=3)
{
En[i]='\0';
}
A[i]=0;
B[i]=0;
}
/*
showA();
printf("\n\n");
showB();
printf("\n\n");
*/
gets(En);
//gets(Tmp);
//test
//printf("En==%s\n",En);
//
if(strcmp(En,"END")==0)
{
break;
}
//计数
no=0;
while(En[no]!='\0')
{
if(En[no]!='_')
{
A[En[no]-'A']++; //从0下标开始
}
else
{
A[ZMAX-1]++;
}
no++;
}
sum=no; //总字母数
/*test
showA();
printf("\n\n");
printf("*sum*%d**\n",sum);
*/
no=getdata(); //不同字母数量
//test
// printf("*no*%d**\n",no);
//
buildtree(no); //产生树
/*test
showHuf(no*2-1);
printf("\n\n");
*/
int f; //father
for(int y=0;y<no;y++) //计算深度
{
deep=1;
f=Huf[y].father;
while(Huf[f].father!=0)
{
f=Huf[f].father;
deep++;
}
B[Huf[y].daibiao]=deep;
}
//压缩后总长
/*test
showB();
printf("\n\n");
*/
besum=8*sum;
afsum=0;
for(int p=0;p<ZMAX;p++)
{
if(A[p]!=0)
{
afsum+=A[p]*B[p];
}
}
printf("%d %d %.1f\n",besum,afsum,(besum*1.0)/afsum);
}
return 0;
}
3. Think Someing
1.可以不用构造出哈夫曼树得到压缩后的长度吗?
2. 一次找最小两个下标有多少种实现?复杂度分别为多少?
3. 有没有变量是可以被删去的?