POJ1521哈夫曼压缩比

哈夫曼压缩


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. 有没有变量是可以被删去的?

猜你喜欢

转载自blog.csdn.net/m0_38062488/article/details/80260566