// 哈夫曼編碼(算法) #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> typedef char *HuffmanCode; //動態分配數組,存儲哈夫曼編碼 typedef struct { unsigned int weight; //用來存放各個結點的權值 unsigned int parent,LChild,RChild; //指向雙親、孩子結點的指針 } HTNode, *HuffmanTree; //動態分配數組,存儲哈夫曼樹//選擇兩個parent為0,且weight最小的結點s1和s2 char alpha[53] = {'a','b','c','d','e','f','g','h','i','j','k','l','m', 'n','o','p','q','r','s','t','u','v','w','x','y','z', 'A','B','C','D','E','F','G','H','I','J','K','L','M', 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}; char alpha_1[53]; int num1[52] = {0}; int num2[52] = {0}; double num3[52] = {0}; int k = 0; double add[52]; double HX = 0.0; double MX = 0.0; void Select(HuffmanTree *ht,int n,int *s1,int *s2) { int i,min; for(i=1; i<=n; i++) { if((*ht).parent==0) { min=i; break; } } for(i=1; i<=n; i++) { if((*ht).parent==0) { if((*ht).weight<(*ht)[min].weight) min=i; } } *s1=min; for(i=1; i<=n; i++) { if((*ht).parent==0 && i!=(*s1)) { min=i; break; } } for(i=1; i<=n; i++) { if((*ht).parent==0 && i!=(*s1)) { if((*ht).weight<(*ht)[min].weight) min=i; } } *s2=min; }//構造哈夫曼樹ht。w存放已知的n個權值 void CrtHuffmanTree(HuffmanTree *ht,int *w,int n) { int m,i,s1,s2; m=2*n-1; *ht=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); for(i=1; i<=n; i++) //1--n號存放葉子結點,初始化 { (*ht).weight=w; (*ht).LChild=0; (*ht).parent=0; (*ht).RChild=0; } for(i=n+1; i<=m; i++) { (*ht).weight=0; (*ht).LChild=0; (*ht).parent=0; (*ht).RChild=0; } //非葉子結點初始化 // printf("\nHuffmanTree: \n"); for(i=n+1; i<=m; i++) //創建非葉子結點,建哈夫曼樹 { //在(*ht)[1]~(*ht)[i-1]的范圍內選擇兩個parent為0 //且weight最小的結點,其序號分別賦值給s1、s2 Select(ht,i-1,&s1,&s2); (*ht)[s1].parent=i; (*ht)[s2].parent=i; (*ht).LChild=s1; (*ht).RChild=s2; (*ht).weight=(*ht)[s1].weight+(*ht)[s2].weight; // printf("%d (%d, %d)\n",(*ht).weight,(*ht)[s1].weight,(*ht)[s2].weight); } printf("\n"); } //哈夫曼樹建立完畢//從葉子結點到根,逆向求每個葉子結點對應的哈夫曼編碼 void CrtHuffmanCode(HuffmanTree *ht, HuffmanCode *hc, int n,char str[],double num[],double HX) { int shu[n]; char *cd; int i,start,p; unsigned int c; hc=(HuffmanCode *)malloc((n+1)*sizeof(char *)); //分配n個編碼的頭指針 cd=(char *)malloc(n*sizeof(char)); //分配求當前編碼的工作空間 cd[n-1]='\0'; //從右向左逐位存放編碼,首先存放編碼結束符 for(i=1; i<=n; i++) //求n個葉子結點對應的哈夫曼編碼 { start=n-1; //初始化編碼起始指針 for(c=i,p=(*ht).parent; p!=0; c=p,p=(*ht)[p].parent) //從葉子到根結點求編碼 if( (*ht)[p].LChild==c) cd[--start]='1'; //左分支標0 else cd[--start]='0'; //右分支標1 hc=(char *)malloc((n-start)*sizeof(char)); //為第i個編碼分配空間 strcpy(hc,&cd[start]); } free(cd); for(i=1; i<=n; i++) printf("HFMC %c is %s\n",str,hc); for(i=1; i<=n; i++) { shu = strlen(hc); //測出碼長 MX += shu*num3; //計算平均碼長 } MX = HX/MX;//計算效率 printf("\n編碼效率n %f\n",MX); printf("\n"); } int countchar(char str[],char a,int n_value) { int n=0; int i = 0; while(i < n_value) { if((str) == a) n++; i++; } return n; } int main() { HuffmanTree HT; HuffmanCode HC; int *w,i,wei,m,value = 0,count = 0,n1 = 0,n2 = 0,j = 0,n = 0; char data; FILE *fp=fopen("in.txt","r"); if(!fp) { printf("can't open file\n"); return -1; } while(!feof(fp)) { value++; data=fgetc(fp); printf("%c",data); if(data>='a'&&data<='z'||data>='A'&&data<='Z') n1++; else if(data>='0'&&data<='9') n2++; } printf("\n字母:%d\n",n1); printf("\n"); fclose(fp); char disbuf[value]; FILE *fq=fopen("in.txt","r"); if(!fq) { printf("can't open file\n"); return -1; } while(count <= value) { fscanf(fq,"%c",&disbuf[count]); count++; } fclose(fq); printf("\n"); for(j = 0; j < 52; j++) num1[j] += countchar(disbuf, alpha[j],n1);//找出各個字母的個數 for( i = 0; i < 52; i++ ) //求每個字母的概率 { add= double(num1)/double(n1); } for( i = 0,j = 1;i < 26; i++) { printf("字母%c\t\t數量%d\t概率%0.3f\t",alpha,num1,add); printf("字母%c\t\t數量%d\t概率%0.3f\t",alpha[i+26],num1[i+26],add[i+26]); } for(i = 0,j = 1; i < 52; i++)//把不為零的字母統計出來,統計他們的個數與符號 { if(num1 != 0) { n++; num2[j] = num1; alpha_1[j] = alpha; j++; } } for( i = 0,j = 1; i < 52; i++ ) //把不為零的字母概率挑選出來 ,計算信源熵 { if(num1 != 0) { HX += add*log10(add); num3[j] = add; //挑選出有概率的字符和其概率; j++; } } HX = - HX/log10(2); //計算信源熵 printf("\n信源熵H(X) %f\n",HX); w=(int *)malloc((n+1)*sizeof(int)); for(i=1; i<=n; i++) { w= num2 ; } CrtHuffmanTree(&HT,w,n); CrtHuffmanCode(&HT,&HC,n,alpha_1,num3,HX);
|