怎麼實現huffman(哈夫曼編碼)以及解碼

 一、編碼

【題目描述】

給定一篇用於通信的英文電文,統計該電文中每個字符出現的頻率,按頻率左小右大的方法爲這些字符建立哈夫曼(Huffamn)樹,並編出每個字符的哈夫曼樹碼,輸出該電文的哈夫曼碼譯文。

 

【輸入】

輸入文件huffman.in是一篇用於通信的英文電文。

【輸出】

輸出文件huffman.out輸出該電文的哈夫曼碼譯文。

 

【輸入輸出樣例1】

huffman.in                             

huffman.out

aaccdddbacbcddddddd

011011000011101001100010001111111

【數據限制】

2<=英文電文字符數<=10000000

統計以上abcd出現的個數。

a:3   b:2    c:4    d:10

構造出哈夫曼樹

a:011         b:010     c  :00          d:1

下面主要通過兩個結構體數組來實現:

struct node1
{ int w, lch, rch, parent;
}ht[2*N0-1+1];

數組下標 1 2 3 4 5 6 7
父節點的數組下標parent 0 0 0 0      
左孩子節點的數組下標lch 0 0 0 0      
右孩子節點的數組下標rch 0 0 0 0      
權值w 3 2 4 10      

-》

數組下標 1 2 3 4 5 6 7
父節點的數組下標parent 5 5 0 0 0    
左孩子節點的數組下標lch 0 0 0 0 2    
右孩子節點的數組下標rch 0 0 0 0 1    
權值w 3 2 4 10 5    

-》.。。。。。。。。

數組下標 1 2 3 4 5 6 7
父節點的數組下標parent 5 5 6 7 6 7 0
左孩子節點的數組下標lch 0 0 0 0 2 5 6
右孩子節點的數組下標rch 0 0 0 0 1 3 4
權值w 3 2 4 10 5 9 19

 

struct node2
{ char ch;//對應的字符abcd
 int start;//編碼的起始位置 注意這個編碼是倒着的 所以這裏用start
 int code[N0];//這個是編碼數組
}hc[N0+1];

大概圖如下面

美工不好啊 大概將就看了啊

下面給出大家想要的程序部分

//#include "stdio.h"
//#include   "string.h " 
#include <iostream>
#include <string>
const int N0=10;
const int N=100;
const int INF=1000000;
struct node1 
{ int w, lch, rch, parent;
}ht[2*N0-1+1];
struct node2
{ char ch;
 int start;
 int code[N0];
}hc[N0+1];
int n,root;//n爲葉子的個數
void readData()
{ char ch;
int num[256]={ 0 };
 n=0;
 freopen( "huffman.in", "r", stdin);//讀文本文件
 while( (ch=getchar()) != EOF )
  num[ch]++;
 for( int i=0; i<=255; i++ )
 { if( num[i] )
  { n++;
   ht[n].w=num[i];
   hc[n].ch=i;
  }
 }
}
void select1( int t, int *s1, int *s2)//用兩個數來記錄沒有在樹上的最小的兩個值,從而進一步生成樹。
{ int w1,w2;
 w1=w2=INF;
 for( int i=1; i<=t; i++ )
  if( ht[i].parent==0 )
   if( ht[i].w<w1 )
   { w2=w1;
    *s2=*s1;
    w1=ht[i].w;
    *s1=i;
   }
   else if( ht[i].w<w2 )
   { w2=ht[i].w;
    *s2=i;
   }
}


void createHufTreeHuCode()
{ int i, s1, s2;
 int child, parent;
 root=2*n-1;
 for( i=n+1; i<=root; i++)
 { select1(i-1, &s1, &s2 );
  ht[i].w=ht[s1].w+ht[s2].w;
  ht[i].lch=s1;
  ht[i].rch=s2;
  ht[s1].parent=ht[s2].parent=i;
 }
 for(  i=1; i<=n; i++)
 { child=i;
  while( child != root )
  { parent=ht[child].parent;
   if( ht[parent].lch==child )
    hc[i].code[hc[i].start++]=0;
   else 
    hc[i].code[hc[i].start++]=1;
   child=parent;
  }
 }

}
void txt2code()
{
 int i,j,m;
 char ch1[N+1]={0};
 freopen( "huffman.in", "r", stdin);
 for (int k=1;k<N+1;k++)
 {
  scanf("%c",&ch1[k]);
 }
 for( j=1,i=1; i<=N; i++)
 { if (ch1[i]==0)
  {
   break;
  }
  while (ch1[i]!=hc[j].ch)
  {
   if (hc[j].ch==0)
   {continue;
   }
   j++;
  }
  for( m=hc[j].start-1; m>=0; m--)
   printf("%d", hc[j].code[m]);
  j=1;
 }
}


int main()
{ 
 readData();
 createHufTreeHuCode();
 freopen("huffman.out", "w", stdout);
 txt2code();
 return 0;
}

二、譯碼

【題目描述】

給定2個輸入文件,第1個輸入文件是用於通信的英文電文,統計該電文中每個字符出現的頻率,按頻率左小右大的方法爲這些字符建立哈夫曼(Huffamn)樹,並編出每個字符的哈夫曼樹碼;第2個輸入文件是已經按第1個輸入文件的英文電文編好的哈夫曼碼,輸出該哈夫曼碼的對應的英文電文。

 

【輸入】

第1個輸入文件爲huffman.in是用於通信的英文電文, 第2個輸入文件codeToTxt.in是已經按第1個輸入文件編好的哈夫曼碼。

【輸出】

輸出文件codeToTxt.out輸出codeToTxt.in文件內容的英文電文。

 

【輸入輸出樣例1】

huffman.in                            

codeToTxt.in

codeToTxt.out

aaccdddbacbcddddddd

011111011000011101001100010001111

adddaccdddbacbcdddd

【數據限制】

2<=英文電文字符數<=10000000


 

#include <iostream>
#include <string>
const int N0=10;
const int N=100;
const int INF=1000000;
struct node1 
{ int w, lch, rch, parent;
}ht[2*N0-1+1];
struct node2
{ char ch;
 int start;
 int code[N0];
}hc[N0+1];
int n,root,num[256];
void readData()
{ char ch;

 n=0;
 freopen( "huffman.in", "r", stdin);
 while( (ch=getchar()) != EOF )
  num[ch]++;//同時得到了兩個東西,一個是字符,一個是個數
 for( int i=0; i<=255; i++ )
 { if( num[i] )
  { n++;
   ht[n].w=num[i];//個數
   hc[n].ch=i;//字符
  }
 }
}
void select1( int t, int *s1, int *s2)
{ int w1,w2;
 w1=w2=INF;
 for( int i=1; i<=t; i++ )
  if( ht[i].parent==0 )
   if( ht[i].w<w1 )
   { w2=w1;
    *s2=*s1;
    w1=ht[i].w;
    *s1=i;
   }
   else if( ht[i].w<w2 )
   { w2=ht[i].w;
    *s2=i;
   }
}
void createHufTreeHuCode()
{ int i, s1, s2;
 int child, parent;
 root=2*n-1;
 for( i=n+1; i<=root; i++)
 { select1( i-1, &s1, &s2 );
  ht[i].w=ht[s1].w+ht[s2].w;
  ht[i].lch=s1;
  ht[i].rch=s2;
  ht[s1].parent=ht[s2].parent=i;
 }
 for(  i=1; i<=n; i++)
 { child=i;
  while( child != root )
  { parent=ht[child].parent;
   if( ht[parent].lch==child )
    hc[i].code[hc[i].start++]=0;
   else 
    hc[i].code[hc[i].start++]=1;
   child=parent;
  }
 }

}


void code2txt()
{ char ch=0;
int i=root;
 freopen( "codeToTxt.in", "r", stdin);
 freopen("codeToTxt.out", "w", stdout);
 while( (ch=getchar()) != EOF )
 {
 
   if(ht[i].lch&&ht[i].rch)
   {if(ch=='0')
    i=ht[i].lch;
   else
    i=ht[i].rch;
   }
   if(ht[i].lch==0&&ht[i].rch==0)
   { printf("%c",hc[i].ch);
    i=root;
   }
    
 }
}


int main()
{ readData();
 createHufTreeHuCode();
 code2txt();
 return 0;
}


 

發佈了58 篇原創文章 · 獲贊 12 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章