1. 程式人生 > >赫夫曼樹編碼解碼實例(C)

赫夫曼樹編碼解碼實例(C)

sta nod 輸入 sign 赫夫曼 spa 字符數組 ++ es2017


//
HuffmanTree.h #include <stdlib.h> #include <stdio.h> #include <string.h> #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;i<n;++i){ if(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 <stdio.h>

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)