哈夫曼编码_静态库


#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
*/



原文地址:https://www.cnblogs.com/IThaitian/p/2752382.html