赫夫曼树编码解码实例(C)

//HuffmanTree.h
#include 
#include 
#include 
#define OVERFLOW -1

typedef struct{
    char data;           //节点所存字符
    unsigned int weight;    //节点权重
    unsigned int parent,lchild,rchild;
}HTNode, *HuffmanTree;     //动态分配数组存储赫夫曼树
typedef char** HuffmanCode;//动态分配数组存储赫夫曼编码表


//从T的1到n个节点中找出没有结合(即parent=0)的节点中权重weight最小的两个节点的下标;用l,r带回;
void Select(HuffmanTree T,int n,int&l,int&r)
{
    HuffmanTree p=T+1;int a=0,b=0;
    for(int i=1;i<=n;++i,++p){
        if(!p->parent){//找出双亲节点为空的节点;
            if(!a){l=i;a=1;}
            else if(!b){r=i;b=1;}
            else if(p->weight<(T+l)->weight||p->weight<(T+r)->weight){
                if((T+l)->weight<=(T+r)->weight)r=i;
                else l=i;
            }
        }
    }
}


//w存放n个字符的权值(均>0),构造赫夫曼树HT,并求出n个字符的赫夫曼编码HC
//HT为赫夫曼树,HC为赫夫曼编码,w为权重数组,n为w长度
void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, char* c, int n){

    if(n<=1) return;
    int m = 2*n-1;
    HT = (HuffmanTree)malloc((m+1)*sizeof(HTNode)); //0号单元未用
    HuffmanTree p;
    int i;
    for(p=HT+1,i=1; i<=n; ++i,++p,++w) *p = {c[i-1],*w,0,0,0};
    for(i=n+1; i<=m; ++i, ++p)         *p = {0,0,0,0,0};

    for(i=n+1; i<=m; ++i){ //建赫夫曼树
        //在HT[1..i-1]选择parent为0且weight最小的两个节点,其序号分别为s1和s2。
        int s1,s2;
        Select(HT, i-1, s1, s2);
        HT[s1].parent = i; HT[s2].parent = i;
        HT[i].lchild = s1; HT[i].rchild = s2;
        HT[i].weight = HT[s1].weight + HT[s2].weight;
    }
    //---从叶子到根逆向求每个字符的赫夫曼编码---
    HC = (HuffmanCode)malloc((n+1)*sizeof(char *)); //分配n个字符编码的头指针向量
    char* cd = (char *)malloc(n*sizeof(char));          //分配求编码的工作空间
    cd[n-1] = '\0';    //编码结束符
    for(i=1; i<=n; ++i){
        //逐个字符求赫夫曼编码
        int start = n-1;  //编码结束符位置
        int c,f;
        for(c=i, f=HT[i].parent; f!=0; c=f,f=HT[f].parent) //从叶子到根逆向求编码
            if(HT[f].lchild == c) cd[--start] = '0';
            else cd[--start] = '1';
        HC[i] = (char *)malloc((n-start)*sizeof(char));  //为第i个字符编码分配空间
        strcpy(HC[i],&cd[start]); //从cd复制编码(串)到HC
    }
    free(cd);  //释放工作空间
}


//输出赫夫曼编码
//HC为赫夫曼编码,w为权重数组,n为w长度,c为字符数组
void PrintHuffmanCode(HuffmanCode HC,int* w,char* c,int n)
{
    char *p;
    int i;
    for(i=1;i<=n;++i){
        printf("字符:%c,权重:%3d,编码:", c[i-1], w[i-1]);
        p=HC[i];
        printf("%s\n",p);
    }
}

//返回某字符的赫夫曼编码
//HC为赫夫曼编码,c为字符数组,n为c长度,ch为要编码的字符
char* EnCode(HuffmanCode HC, char* c, char ch, int n)
{
    int i;
    for(i=0;iif(c[i]==ch){
            char *p = HC[i+1];
            return p;
        }
    }
}

//解码
//s为待解码字符串,HT为赫夫曼树
char* DeCode(const char*s, HuffmanTree HT){
    int i; HuffmanTree p=HT;
    static char result[500];
    int j=0;

    //寻找根节点
    while(p->parent!=0) p++;
    const HuffmanTree root = p;

    for(i=0; i<strlen(s); ++i){
        if(s[i]=='0'){
            if(p->lchild!=0){
                p=HT+p->lchild;
            }
        }
        else if(s[i]=='1'){
            if(p->rchild!=0){
                p=HT+p->rchild;
            }
        }
        if(p->lchild==0&&p->rchild==0){
            result[j]=p->data;++j;
            p = root;
        }
    }
    result[j] = '\0';
    return result;
}

#include "HuffmanTree.h"
#include 

int main(void){

    char s[500];

READ:
    printf("请输入一段话:");
    gets(s);


    int i=0,w[1000]={0},*word; char *c; //word记录权值,c记录字符

    while(s[i]!='\0'){ //出现次数计数
        w[s[i]+500]++;
        ++i;
    }

    int j=0; word = (int*)malloc(sizeof(int));
             c = (char*)malloc(sizeof(char));
    for(i=-500;i<500;++i){
        if(w[i+500]!=0){
            word = (int*)realloc(word,(j+1)*sizeof(int));
            c = (char*)realloc(c,(j+1)*sizeof(char));
            word[j] = w[i+500];
            c[j] = i;
            ++j;
        }
    }

    const int len = j; //字符数组、权重数组长度


    if(len==1){
        printf("请输入大于1种字符!\n");
        goto READ;
    }

    HuffmanCode HC;HuffmanTree HT;
    HuffmanCoding(HT,HC,word,c,len);
    PrintHuffmanCode(HC,word,c,len);

    i=0;
    printf("赫夫曼编码后结果为:");
    char code[1000]={'\0'};
    while(s[i]!='\0'){
        strcat(code,EnCode(HC,c,s[i],len));
        ++i;
    }
    printf("%s\n",code);

    printf("解码结果为:%s",DeCode(code,HT));
    printf("\n");
    getchar();
    return 0;
}

运行截图:
赫夫曼树编码解码实例(C)_第1张图片

赫夫曼树编码解码实例(C)_第2张图片

赫夫曼树编码解码实例(C)_第3张图片

你可能感兴趣的:(数据结构,学习笔记,c语言,赫夫曼树)