hafuman编码.c

来自「哈夫曼编码(hufuman code)c实现」· C语言 代码 · 共 236 行

C
236
字号
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define leave 256
#define bignumber 987654321
#define max 256
int  n=0; /* 叶子树*/
int  m=0 ; /* 结点总数*/
char s[1000];/*输入字符串*/
int len;/*字符串长度*/
/***************统计字符与其频率的结构********/
struct letters
{
    char ch;
    int weight;
}letter[max];
/**************Huffman树的结构类型*************/
/* huffman树的静态三叉链表表示*/
typedef struct
{
    /* 结点型*/
    int weight; /* 权值*/
    int lchild; /* 左孩子链*/
    int rchild; /* 右孩子链*/
    int parent; /* 双亲链*/
}
HTNODE;
typedef HTNODE* HuffmanT;
HuffmanT T;
/************编码的结构类型************/
typedef struct
{
    char  ch;   //存储字符
    char  bits[leave+1]; //字符编码位串
}
CodeNode;
typedef CodeNode *HuffmanCode;
HuffmanCode H;
/****************************************/

void InitHT(HuffmanT T);//初始化
void InputW(HuffmanT T);/* 输入权值*/
void SelectMin(HuffmanT T,int k, int *p1,int * p2);//选择最小权值和次小权值

void CreartHT(HuffmanT T)/*构造huffam树,T[m-1]为其根*/
{
    int i ,p1 ,p2;

    InitHT(T);
    InputW(T);
    for (i = n;i < m;i++)
    {
        /*  n-1次合并最小和次小权值*/
        SelectMin(T, i-1, &p1, &p2);
        T[p1].parent =T[p2].parent = i ;
        T[i].lchild= p1;
        T[i].rchild= p2;
        T[i].weight =T[p1].weight + T[p2].weight;
    }
}
/*初始化huffman树,权值初始为0,父节点与儿子结点初始为-1*/
void InitHT(HuffmanT T)
{
    int i;

    for (i=0;i<m;i++)
    {
        T[i].weight=0;
        T[i].lchild=T[i].rchild=T[i].parent=-1;
    }
}
/********************根据字符频率,输入权值********************************/
void InputW(HuffmanT T)
{
    int i;
    for (i=0;i<n;i++)
    {
        T[i].weight=letter[i].weight;
    }
}
/************选择已经构造的内节点和外接点之中最小的和次小的权值**********/
void SelectMin(HuffmanT T,int k, int *p1,int * p2)
{
    int a,min1=bignumber,min2=bignumber;
    for (a=0;a<=k;a++)
        if (T[a].weight<min1&&T[a].parent==-1)
        {
            *p1=a;//得到最小权值
            min1=T[a].weight;//临时存放最小权值
        }
    for (a=0;a<=k;a++)
        if ((T[a].weight<min2)&&T[a].parent==-1&&a!=*p1)
        {
            *p2=a;//得到次小权值
            min2=T[a].weight;//临时存放次小权值
        }
}
/***********统计出现的字符,并存入相应的权值*****************/
void weight_count(char *s,int len)
{
    int i,j,k;
    j=k=0;
    for (i=0;i<len;i++)//将统计出现字符的结构初始化
    {
        letter[i].ch='\0';
        letter[i].weight=0;
    }
    for (i=0;i<len;i++)
    {
        for (k=0;k<=j;k++)
        {
            if (letter[k].ch==s[i])
            {
                letter[k].weight++;//对于出现过的字符,进行频率统计
                break;
            }
        }
        if (k==j+1)
        {
            letter[j].ch=s[i];//没出现的字符要将之储存
            letter[j++].weight++;
        }
    }
    n=j;
}
/**************编码************************/
void CharSetHuffmanEncoding(HuffmanT T, HuffmanCode H)/*编码*/
{
    /*根据Huffman树T 求Huffman编码表 H*/
    int c, p, i,k;           /* c 和p 分别指示T 中孩子和双亲的位置*/
    char cd[n+1];           /* 临时存放编码*/
    int start;             /* 指示编码在cd 中的位置 */

    memset(cd,'\0',sizeof(cd));                      /* 存储空间初始化*/
    for ( i =0; i <n;  i++)
    {
        /* 依次求叶子T[i]的编码 */
        H[i].ch=letter[i].ch;                        /* 读入叶子T[i]对应的字符*/
        start=n;                                     /* 编码起始位置的初值*/
        c =i;                                        /* 从叶子T[i]开始上溯*/
        while ( (p=T[c].parent)>=0)
        {
            /* 直到上溯到T[c]是树根位置*/
            cd[--start]=(T[p].lchild==c)? '0' : '1'; /* 若T[c]是T[p]的左孩子,则生成代码0,否则生成代码1*/
            c=p;      /* 继续上溯*/
        }
        strcpy(H[i].bits,&cd[start]);                /*复制编码为串于编码表H*/
        printf("%-10c----------%10s\n",H[i].ch,H[i].bits);
    }
    printf("The %s\'s encoding text is:\n",s);       /*将加密的文本打印*/
    for (i=0;i<len;i++)
        for (k=0;k<n;k++)
            if (s[i]==H[k].ch)
                printf("%s",H[k].bits);
}
/**********************译码*********************/
void CharSetHuffmanDecoding(HuffmanT T, HuffmanCode H)
{
    int j=0;
    int start=m-1;//从树根开始查找

    while (s[j]!='\0')
    {
        if (s[j] == '0' && T[start].lchild != -1)//遇见0,向左儿子走
            start = T[start].lchild;
        else if (s[j] == '1' && T[start].rchild != -1)//遇见1,向右儿子走
            start = T[start].rchild;
        else
        {
            printf("%c", letter[start].ch);//如果走到了外结点,就打印该节点
            start = m - 1;
            j--;
        }
        j++;
    }
    printf("%c\n", letter[start].ch);//将最后一个字符打印
}
/********************主函数************************/
int main()
{
    char a;
    int i;
    /**************输入文本***********************/
    printf("Please input a english text:\n");
    while (gets(s)!=NULL)
    {

        len=strlen(s);
        weight_count(s,len);
        printf("\nThe letters\' frequence are:\n");
        for (i=0;i<n;i++)                                   /*打印频率的统计结果*/
            printf("%c %d\n",letter[i].ch,letter[i].weight);
        printf("The encoding letters are:\n");
        m=2*n-1;
        T=(HuffmanT)malloc(m*sizeof(HTNODE));               //为huffman树申请空间
        H=(HuffmanCode)malloc(n*sizeof(CodeNode));          //为huffman编码申请空间
        CreartHT(T);//建huffman树
        /*************encode*********************/
        CharSetHuffmanEncoding(T,H);                        //利用huffman树进行编码

        printf("\n\nDo you want to exist?(y to quit,n to decode):");
        if (getchar()=='y')//退出选择y
        {
            free(T);
            free(H);
            return 0;
        }
decode:
        getchar();//读入回车,消除影响
        /***********decode*****************/
        printf("Please input the encoding text that you want to decode.\n");
        gets(s);//输入01字符串
        CharSetHuffmanDecoding(T,H);//利用编完的huffman编码进行译码
        printf("\n\nDo you want to exist?(y to quit,\'1\' to encode,\'2\' to decode):");
        if ((a=getchar())=='y')//选择y退出
        {
            free(T);
            free(H);
            return 0;
        }
        else if (a=='1')//选择1进行编码
        {
            free(T);
            free(H);
            getchar();//读入回车,消除影响
            printf("Please input a english text:\n");
            continue;
        }
        else if (a=='2')//选择2进行译码
        {
            goto decode;
        }
    }
    return 0;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?