哈夫曼编码_静态库

 
   
#include <stdio.h>

#include <string.h>

#define N 50        //叶子结点数

#define M 2*N-1        //树中结点总数

typedef struct//哈夫曼树的节点

{

    char data[5];    //结点存储的单词

    int weight;        //权重(该单词出现次数)

    int parent;        //双亲结点

    int lchild;        //左孩子结点

    int rchild;        //右孩子结点

} HTNode;

typedef struct//哈夫曼编码

{

    char cd[N];    //叶子节点对应的哈夫曼编码

    int start; //指向哈夫曼编码cd[]的最开始字符(从下标start开始到n为有效的哈夫曼编码)

} HCode;



void CreateHT(HTNode ht[],int n);//构造

void CreateHCode(HTNode ht[],HCode hcd[],int n);//编码

void DispHCode(HTNode ht[],HCode hcd[],int n);//输出编码

void main()

{

    int n=15;//15个单词(叶节点)

    ////初始化

    char *str[]={"The","of","a","to","and","in","that","he","is","at","on","for","His","are","be"};

    int fnum[]={1192,677,541,518,462,450,242,195,190,181,174,157,138,124,123};

    HTNode ht[M];//节点

    HCode hcd[N];//编码

    for (int i=0;i<n;i++)

    {

        strcpy(ht[i].data,str[i]);

        ht[i].weight=fnum[i];

    }

    CreateHT(ht,n);//构造哈夫曼树

    CreateHCode(ht,hcd,n);//根据哈夫曼树建立哈夫曼编码

    DispHCode(ht,hcd,n);//输出哈夫曼编码

    printf("\n");

}





void CreateHT(HTNode ht[],int n)

{

    int i,k,lnode,rnode;

    int min1,min2;

    for (i=0;i<2*n-1;i++)//ht[]初始化---所有结点的相关域置初值-1

        ht[i].parent=ht[i].lchild=ht[i].rchild=-1;

    //构造哈夫曼树///////////////////////////////

    for (i=n;i<2*n-1;i++)

    {

        min1=min2=32767;//最小权重和次小权重

        lnode=rnode=-1;//最小两个权重位置(节点下标)

        //从已有的节点且未构造二叉树的节点中选取权重最小的两个节点

        for (k=0;k<=i-1;k++)//树中现有i个节点

            if (ht[k].parent==-1)//尚未构造二叉树的结点

            {

                if (ht[k].weight<min1)//k号节点权重比最小权重min1还小

                {

                    min2=min1;rnode=lnode;//次小权重min2取最小权重min1

                    min1=ht[k].weight;lnode=k;//最小权重min1取k号节点对应的权重

                }

                else if (ht[k].weight<min2)//k号节点权重大于最小权重,小于次小权重min2

                {

                    min2=ht[k].weight;rnode=k;//次小权重min2取k号节点权重

                }

            }

        ht[lnode].parent=i;ht[rnode].parent=i;//权重最小的两个节点构造以i号节点为父节点的二叉树

        //新增i号节点(新增节点没有data域)

        ht[i].weight=ht[lnode].weight+ht[rnode].weight;

        ht[i].lchild=lnode;ht[i].rchild=rnode;

    }

}

void CreateHCode(HTNode ht[],HCode hcd[],int n)

{

    int i,f,temp;

    HCode hc;

    for (i=0;i<n;i++)    /*根据哈夫曼树求哈夫曼编码*/

    {

        //////对叶节点i对应单词---进行编码////

        hc.start=n;//hc.cd[]中编码存放的起始位置(从start开始到n为编码存储区)(编码下标范围是0~N-1)

        temp=i;//当前节点c取叶节点i

        f=ht[temp].parent;        

        while (f!=-1)//当前节点c存在父节点

        {

            if (ht[f].lchild==temp)//当前c节点是其父节点的左孩子节点

                hc.cd[hc.start--]='0';//编码

            else hc.cd[hc.start--]='1';//当前c节点是其父节点的右孩子节点

    

            temp=f;//取c的父节点为新的当前节点c

            f=ht[temp].parent;//取当新的当前节点c的父节点f

        }

        hc.start++;//(从下标hc.start开始存储到hc.start=n结束)---start指向哈夫曼编码最开始字符

        ////////////////////////////////////////

        hcd[i]=hc;//叶节点i对应单词的哈夫曼编码hc存入编码表hcd[i]  

    }

}

void DispHCode(HTNode ht[],HCode hcd[],int n)//输出哈夫曼编码

{

    int i,k;

    int CodeSum=0,WeightAdd=0;

    printf("输出哈夫曼编码:\n"); 

    for (i=0;i<n;i++)//对于每个单词(叶节点)

    {

        int CountLen=0;

        printf("%s:\t",ht[i].data);//输出单词

        for (k=hcd[i].start;k<=n;k++)//输出单词(叶节点)编码

        {

            printf("%c",hcd[i].cd[k]);

            CountLen++;//统计i号单词编码长度

        }

        WeightAdd+=ht[i].weight;//统计叶节点权重和(即所有单词总数)

        CodeSum+=ht[i].weight*CountLen;//得到总的编码量(即所有单词的编码总量)

        printf("\n");

    }

    printf("平均每个单词的编码长度=%g\n",1.0*CodeSum/WeightAdd);//输出每个单词的编码平均长度

}







/*

输出哈夫曼编码:

The:    01

of:     101

a:      001

to:     000

and:    1110

in:     1101

that:   11110

he:     11001

is:     11000

at:     10011

on:     10010

for:    10001

His:    10000

are:    111111

be:     111110

平均每个单词的编码长度=3.56208



Press any key to continue

*/

 




你可能感兴趣的:(编码)