1. 程式人生 > >對26個英文字母進行huffman編碼

對26個英文字母進行huffman編碼

<ol><li class="alt"><span><span class="comment">1、建立哈夫曼樹</span> </span></li><li><span><span class="comment">2、從每個葉結點回溯到root的路徑,並記錄路徑,則為哈夫曼編碼</span> </span></li><li class="alt"><span><span class="comment">3、查表方式獲得每個字元的哈夫曼編碼</span> </span></li></ol>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
///----------------------定義結點資料---------------
#define leave 26
#define node (26*2-1)
typedef struct nodee
{
    char character;
    float weight;
    int lson;
    int rson;
    int par;
}Node,*pnode;

typedef struct code
{
    int hufcode[leave];///葉節點最長編碼位數應該為樹的最長路徑 ,儲存編碼結果
    int sta;  ///編碼起始位(相對編碼陣列)
    char Char; ///編碼的字元值

}Code,*pcode;

///----------------------構造哈夫曼樹----------------
void huffman(Node ht[],float wt[])
{
    int i,j,x1,x2;
    float min1,min2;
///初始化結點陣列ht  ,即對huffman樹進行初始化
    for(i=0;i<node;i++)
    {
        ht[i].par=-1;
        ht[i].lson=-1;
        ht[i].rson=-1;
        if(i<leave)
        {
            ht[i].weight=wt[i];
            ht[i].character=i+65;///A-Z的ASCii碼
        }
        else
        {
            ht[i].weight=0;
            ht[i].character='?';///生成的中間結點字元值標記為'?'
        }
    }
///控制n-1次結點的結合(若有n個葉結點)
    for(i=1;i<leave;i++)
    {
        min1=min2=100;///min1、min2記錄當前最小、次小權值
        x1=x2=0; ///x1、x2記錄當前最小次小權值結點的位置(陣列標號)
        for(j=0;j<leave-1+i;j++) ///在[0-j]範圍內找最小次小權值結點
        {
            if(ht[j].par==-1 && ht[j].weight<min1)///parent元素的判斷是為了排除已結合過的結點,結合過的結點parent有正值
            {
                min2=min1;///當前結點權值小於最小值,所以當前結點變成最小權值結點,原最小結點變成原來的次小結點
                x2=x1;
                min1=ht[j].weight;
                x1=j;
            }
            else
            {
                if(ht[j].par==-1 && ht[j].weight<min2) ///當前結點權值大於最小值,小於次小值,則取代次小結點
                {
                    min2=ht[j].weight;
                    x2=j;
                }
            }
        }

        ///將找到的最小、次小權值結點結合成樹,為其父結點賦值,可見該哈夫曼樹的根節點應該是ht陣列最後一個結點ht[node-1]
        ht[x1].par=leave-1+i;
        ht[x2].par=leave-1+i;
        ht[leave-1+i].weight=ht[x1].weight+ht[x2].weight;
        ht[leave-1+i].lson=x1;
        ht[leave-1+i].rson=x2;
    }
}
///--------------------獲取並儲存每個葉節點的哈夫曼編碼供解碼時查詢--------------------------
void codeht(Node ht[],Code hc[])
{
    int i,j,d,p;
    Code x;
///依次每個葉結點(在哈夫曼結點陣列的最前面的空間中)尋找雙親直到root,記錄路徑,路徑就是哈夫曼編碼

    for(i=0;i<leave;i++)///從每個字母都向上找尋根節點,使得整個樹完整的編碼
    {
        x.Char=ht[i].character;
        x.sta=leave-1;///預設編碼起點為編碼陣列最後一位
        d=i;
        p=ht[i].par;
        while(1)
        {
            if(ht[p].lson == d)
                x.hufcode[x.sta]=0;///預設編碼為左0右1
            else if(ht[p].rson==d)
                x.hufcode[x.sta]=1;
            else
               printf("ERROR!!");


            d=p;
            p=ht[d].par;///繼續向著根延伸編碼
            if(p==-1)break;///到了26個字母以外停止,ht[i]為root結點退出迴圈,說明已經回溯到了根結點

            x.sta--;
        }
        for(j=x.sta;j<leave;j++)
        {
            hc[i].hufcode[j]=x.hufcode[j];
        }
        hc[i].sta=x.sta;
        hc[i].Char=x.Char;
    }
}
///--------------------輸出每個字元的的哈夫曼編碼------------------------
void printcode(Code hc[])
{
    int i,j;
    for(i=0;i<leave;i++)
    {
        printf("字母%c的huffman編碼為:",hc[i].Char);
        for(j=hc[i].sta;j<leave;j++)
        {
            printf("%d",hc[i].hufcode[j]);
        }
        printf("\n");
    }
}
///-----------------------查詢字元的編碼---------------------------
void findcode(Code hc[])
{
    int i,j;
    char x;
    printf("請輸入一個大寫英文字母:");
    while(scanf("%c",&x)!=EOF)
    {
        getchar();
        for(i=0;i<leave;i++)
        {
            if(x==hc[i].Char)
            {
                printf("字元%c的huffman編碼為:",x);
                for(j=hc[i].sta;j<leave;j++)
                {
                    printf("%d",hc[i].hufcode[j]);
                }
                printf("\n");
            }
        }
        printf("請輸入一個大寫英文字母:");
    }


}

///---------------------主函式-----------------------
int main()
{
    Node huftree[node];///存放所有結點資料
    Code hcode[leave];///存放所有的編碼結果
    ///存放葉結點權值
    float wt[leave]={0.0856,0.0139,0.0297,0.0378,0.1304,0.0289,0.0199,0.0528,0.0627,0.0013,0.0042,0.0339,0.0249,0.0707,0.0797,0.0199,0.0012,0.0677,0.0607,0.1045,0.0249,0.0092,0.0149,0.0017,0.0199,0.0008};
    huffman(huftree,wt);
    codeht(huftree,hcode);
    printcode(hcode);///呼叫可以輸出所有的字母編碼
    findcode(hcode);
    return 0;
}