赫夫曼編碼實現

赫夫曼編碼註釋的講解

大家知道電報吧,就是這種編碼。是一種前綴編碼。大家可以去數據結構的書中看詳細的內容,已經很清楚了餓

因爲涉及到結構體和數據結構,所以比較難讀懂,我就不細講了。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
#define N 100
typedef struct hufmantnode{
    int weight;
    int left,right,parent;
}HUFNODE,*HUFTREE;

int select_two_min(HUFTREE HT,int n,int *min,int *min_second){ //從樹的節點中選出兩個最小的。並且partent是零
    int _min,_min_second;
    int i;
    int count=0;
    if(n<2) return -1;
    for(i = 1;i<=2*n-1;i++){
        if(count == 2)break;
        else if(count == 0){
            if(HT[i].parent == 0){_min = HT[i].weight;*min = i;count++;}
            else continue;
        }
        else if(count == 1){
            if(HT[i].parent == 0){
                if(HT[i].weight < _min){_min_second = _min;*min_second = *min;*min = i;_min = HT[i].weight;}
                else{_min_second = HT[i].weight;*min_second = i;count++;}
            }
            else continue;
        }
    }
    while(i<=2*n-1){
        if(HT[i].parent) {i++;continue;}
        else if(HT[i].weight <= _min&&HT[i].weight!='0'){       
            _min_second = _min;*min_second = *min;
            _min = HT[i].weight;*min = i;
        }
        else if(HT[i].weight <= _min_second&&HT[i].weight!='0'){
            _min_second = HT[i].weight;*min_second = i;
        }
        i++;
    }
    return 1;
   
}

int hufman(int *weight,int n,char ***HC,HUFTREE *tree)//這裏用到了三級指針,因爲想改變一個二級指針的地址,這裏大家好好理解。有點繞,呵呵
{
    int i = 1;
    char **code;
    char* temp;
    HUFTREE HT = *tree;
    HT = (HUFTREE)malloc((2*n)*sizeof(HUFNODE));//對於赫夫曼樹若有n個權重則會有2n-1個節點,這樣我分配2n個節點,就把下標爲0的節點捨去不用了。下面也有同樣的例子。
    if(!HT){
        printf("no free mem\n");exit (-1);
    }
    while(i <=n )//對權重節點的初始化
        {/*HT[i] = {weight[i-1],0,0,0};i++;*/
            HT[i].weight=weight[i-1];
            HT[i].parent=0;
            HT[i].left=0;
            HT[i].right=0;
            i++;
        }
    while(i<=2*n-1)//對要生成的節點的初始化
        {/*HT[i] = {'0',0,0,0};i++;*/ //我原本這樣賦值,但會有語法錯,這樣估計在c中是不允許的吧!
            HT[i].weight='0';
            HT[i].parent=0;
            HT[i].left=0;
            HT[i].right=0;
            i++;
        }
    for(i=n+1;i<=2*n-1;i++){  //第一個for實現樹的建立
        int min,min_second;
        select_two_min(HT,n,&min,&min_second);
        HT[min].parent = i;
        HT[min_second].parent = i;
        HT[i].weight = HT[min].weight+HT[min_second].weight;
        HT[i].left = min;HT[i].right = min_second;
    }
    *HC= (char **)malloc(sizeof(char *)*(n+1));
    code = *HC;
    temp= (char*)malloc(sizeof(char)*(N+1));//臨時存放編碼結果
    if(!temp) {printf("no free mem \n");exit (-1);}
    for(i=1;i<=n;i++){
        int k=N;
        int p;int z;
        code[i] = (char *)malloc(N*sizeof(char));
        temp[k] = '\0';
        for(z=i,p = HT[z].parent;p != 0;z = p,p = HT[p].parent){
            if(HT[p].left == z)
                temp[--k] = '0';
            else
                temp[--k] = '1';   
        }
        strcpy(code[i],temp+k);//將編碼存放到hunmancode【i】中。
    }
    return 1;
}

int
main(void)
{
    int weight[26];  //定義一個權重數組,存放26個英文字母
    int n = 26;
    char **hufmancode;//存放轉換後的編碼。是一個二級指針,每一個指針放一個字符串。
    HUFTREE HT; //定義赫夫曼樹
    int i;
    char temp = 'a';
    for(i=0;i<n;i++)
        weight[i] = (int)(temp++); //初始化權重數組,賦值爲26個字母
    putchar('\n');
    hufman(weight,n,&hufmancode,&HT);
    for (i = 1;i<=n;i++)//打印結果
        printf("%c\t\t%s\n",weight[i-1],hufmancode[i]);
    system("pause");
}
//select_two_min 這個函數希望大家好好看看,如果你會從一堆數中找到兩個最小數,那麼會很容易讀懂,原理是一樣的,不過我個人認爲自己的算法(先找兩個數做基準,再循環比較,進行更新)不是很高效,誰有好方法可以給我留言。呵呵

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章