赫夫曼編碼註釋的講解
大家知道電報吧,就是這種編碼。是一種前綴編碼。大家可以去數據結構的書中看詳細的內容,已經很清楚了餓
因爲涉及到結構體和數據結構,所以比較難讀懂,我就不細講了。
#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 這個函數希望大家好好看看,如果你會從一堆數中找到兩個最小數,那麼會很容易讀懂,原理是一樣的,不過我個人認爲自己的算法(先找兩個數做基準,再循環比較,進行更新)不是很高效,誰有好方法可以給我留言。呵呵