huffman编码的实现与详解

本文介绍了一种哈夫曼编码的实现方法,包括定义结构体、创建哈夫曼树及编码过程。通过输入字符及其权重,程序能够构建哈夫曼树并为每个字符分配最优前缀编码。
首先我们看看它的原理。


过程很简单

1:首先定义结构体

/* *************huffman code的实现**************** */
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct{
    float weight;
    int parent,lchild,rchild;
    char value;

}Node;//定义结构体,value储存字符本身,weight表示权值。
int n;//叶子结点的个数
Node *tree;//树的指针
2:根据输入的n创建相应的2*n-1个结点,并进行处理。

void CreateTree()
{
    int i;
    printf("-----------------welcome to the super huffmancode------------------\n");
    printf("please enter the number of the words:\n");
    scanf("%d",&n);
    printf("please enter the word and it's weight(such as A 12.3):\n");
    tree=(Node*)malloc(sizeof(Node)*(2*n-1));
    for(i=0;i<n;i++)
    {
        getchar();//吸收回车
        scanf("%c%f",&tree[i].value,&tree[i].weight);
        tree[i].parent=tree[i].lchild=tree[i].rchild=-1;

    }//叶子结点处理完毕
    for(;i<2*n-1;i++){
            tree[i].weight=0;
            tree[i].parent=tree[i].lchild=tree[i].rchild=-1;
    }//接着处理其余结点
    CombineNode();
}
原理就是根据输入的n申请内存(都假设申请成功,并未判断是否成功),接着处理前面n个结点,前面n个叶子结点的权值由用户输入,后面的结点的权值都为0,并且初始化全部结点的双亲结点以及孩子结点都为-1.

4:接着进入CombineNode函数将结点的关系梳理出来。
void CombineNode()//结合两结点,供建树使用
{
    int i,j,x1,x2,m1,m2;//x1,x2分别储存最小的两个权值的结点的下标,m1,m2分别为所对应的权值。
    for(i=0;i<n-1;i++)//一共有n个结点,需要连接n-1次,这也是为什么其余的结点为n-1个的原因,用来做bond
    {
        m1=m2=1000000;//先假设权值都为一个非常大的值,并且x1,x2随意取
        x1=x2=0;
        for(j=0;j<n+i;j++)//最开始是从前面n个中选出两个最小的,后面随着后续加入使用的连接结点的增多,慢慢扩大为从n+i个中选出最小的两个,但是所选用的两个结点必须是没用父亲结点的结点,所以if判断中还有一个tree[j].parent==-1.
        {
            if(tree[j].weight<m1&&tree[j].parent==-1)
            {
                m2=m1;
                x2=x1;
                m1=tree[j].weight;
                x1=j;
            }
            else if(tree[j].weight<m2&&tree[j].parent==-1)
            {
                m2=tree[j].weight;
                x2=j;
            }

        }
        tree[x1].parent  = n+i;//经过一个小循环(j所控制的循环),就能选出两个没有父亲结点且权值最小的结点用第n+i个结点进行连接
        tree[x2].parent  = n+i;
        tree[n+i].weight = tree[x1].weight + tree[x2].weight;
        tree[n+i].lchild = x2;
        tree[n+i].rchild = x1;
    }
}

5:树建好了,接下来就是编码了,通过叶子结点往根节点从而获取huffman编码。
char ** encode()
{
    char **p,*temp;//temp用来临时存放每个字符所对应的编码
    int i,j,start,c,f;//i,j循环变量,start用来记录每个字符的编码所在的起始位置,毕竟不是每个字符的编码都是n个长度。
    temp=(char*)malloc(sizeof(char)*n);//申请temp的内存,仅需要n个char的空间即可。
    temp[n-1]='\0';//让temp有个结尾字符
    p=(char**)malloc(sizeof(char*)*n);//p是指向一堆字符指针的指针,它最后的元素是指向每个不同字符所对应编码的首字符。例如,p[0]就是第0个字符的编码的首字符。
    for(i=0;i<n;i++){//前面n个结点均是叶子结点,所以直接从i=0到i=n-1的结点往根找,直到到一个没有父亲结点的结点,也就是根结点
        start=n-1;//最初让start处在刚刚设立结尾字符的位置
        for(c=i,f=tree[i].parent;f!=-1;c=f,f=tree[f].parent)
            if(tree[f].lchild==c)   temp[--start]='0';//不停的判断,如果是左孩子则先让start-1,再赋值为0
            else temp[--start]='1';//否则就是赋值为1
        p[i]=(char*)malloc((n-start)*sizeof(char));//依据刚才所走过的路径长度申请内存,并让最初申请的p的元素指向该段内存
        strcpy(p[i],&temp[start]);//此时start就正好是字符所对应编码的起始位置,直接将temp储存的编码复制给p[i]对应内存中
    }
    free(temp);//释放中间申请的临时储存字符编码的内存
    return p;
}

6:main函数如下
int main()
{
    int i;
    char **p;
    CreateTree();
    p=encode();
    printf("Finished processing.........................\n");
    for(i=0;i<n;i++)//输出huffman 编码
    {
        printf("%c's huffmancode is %s\n",tree[i].value,p[i]);
    }
    return 0;
}
总代码如下:

/* *************huffman code的实现**************** */
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct{
    float weight;
    int parent,lchild,rchild;
    char value;


}Node;//定义结构体,value储存字符本身,weight表示权值。
int n;//叶子结点的个数
Node *tree;//树的指针
void CombineNode()//结合两结点,供建树使用
{
    int i,j,x1,x2,m1,m2;//x1,x2分别储存最小的两个权值的结点的下标,m1,m2分别为所对应的权值。
    for(i=0;i<n-1;i++)
    {
        m1=m2=1000000;
        x1=x2=0;
        for(j=0;j<n+i;j++)
        {
            if(tree[j].weight<m1&&tree[j].parent==-1)
            {
                m2=m1;
                x2=x1;
                m1=tree[j].weight;
                x1=j;
            }
            else if(tree[j].weight<m2&&tree[j].parent==-1)
            {
                m2=tree[j].weight;
                x2=j;
            }


        }
        tree[x1].parent  = n+i;
        tree[x2].parent  = n+i;
        tree[n+i].weight = tree[x1].weight + tree[x2].weight;
        tree[n+i].lchild = x2;
        tree[n+i].rchild = x1;
    }
}
void CreateTree()
{
    int i;
    printf("-----------------welcome to the super huffmancode------------------\n");
    printf("please enter the number of the words:\n");
    scanf("%d",&n);
    printf("please enter the word and it's weight(such as A 12.3):\n");
    tree=(Node*)malloc(sizeof(Node)*(2*n-1));
    for(i=0;i<n;i++)
    {
        getchar();//吸收回车
        scanf("%c%f",&tree[i].value,&tree[i].weight);
        tree[i].parent=tree[i].lchild=tree[i].rchild=-1;


    }//叶子结点处理完毕
    for(;i<2*n-1;i++){
            tree[i].weight=0;
            tree[i].parent=tree[i].lchild=tree[i].rchild=-1;
    }//接着处理其余结点
    CombineNode();
}
char ** encode()
{
    char **p,*temp;
    int i,j,start,c,f;
    temp=(char*)malloc(sizeof(char)*n);
    temp[n-1]='\0';
    p=(char**)malloc(sizeof(char*)*n);
    for(i=0;i<n;i++){
        start=n-1;
        for(c=i,f=tree[i].parent;f!=-1;c=f,f=tree[f].parent)
            if(tree[f].lchild==c)   temp[--start]='0';
            else temp[--start]='1';
        p[i]=(char*)malloc((n-start)*sizeof(char));
        strcpy(p[i],&temp[start]);
    }
    free(temp);
    return p;
}


int main()
{
    int i;
    char **p;
    CreateTree();
    p=encode();
    printf("Finished processing.........................\n");
    for(i=0;i<n;i++)
    {
        printf("%c's huffmancode is %s\n",tree[i].value,p[i]);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值