1. 程式人生 > >電文的編碼和譯碼(哈夫曼樹的應用)

電文的編碼和譯碼(哈夫曼樹的應用)

一、        實驗環境

學寶虛擬機器,VC6.0

二、        實驗目的

從鍵盤接收一串電文字元,輸出對應的哈夫曼編碼,同時能翻譯哈夫曼編碼生成的程式碼串,輸出對應的電文字元。

三、        實驗內容

1.用C語言實現二叉樹的鏈式(二叉連結串列)儲存結構;

2.實現二叉樹的基本操作的有關演算法(二叉樹的建立、各種遍歷等);

3.定義二叉樹的靜態連結串列結構,並利用這種結構儲存哈夫曼樹,利用哈夫曼樹解決編碼及譯碼的實際應用問題。

四、        資料結構與演算法思想描述

(1)建立哈夫曼樹:

若已知n個字元的出現概率的“權值”,構造出具有2n-1個結點的哈夫曼樹(採用靜態連結串列儲存結構),

(2)編碼:

  從哈夫曼樹的葉節點出發,通過雙親找到h[f],通過h[f]的左孩子和右孩子來判斷該葉子是左分支還是右分支。如果是右邊,則為‘1’。反之為‘0’。放入陣列cd[start]裡,重複上述過程,直至找到樹根。倒序輸出陣列的編碼值。

(3)譯碼:

步驟1:設計一迴圈結構接收使用者輸入的二進位制程式碼存入ch[1..m],每迴圈一次接收一個“0”或“1”,同時記錄程式碼的長度;最後將長度存入m中;設k指標的初值=1;

步驟2:將f指標指向根節點。利用指標k掃描到二進位制程式碼ch[]的第k位,若當前第k位二進位制數ch[k] =“0”則f往其左孩子移動,若ch[k]=“1”,則f往其右孩子移動;f每移動一步時執行一次k++;直到發現f的左孩子(或右孩子)為“空”時,則f遇到葉子結點,列印f所指葉子結點的data中存放的值;

步驟3:當k<=m時,則又轉步驟2,繼續掃描二進位制程式碼中的剩餘數字,否則譯碼完成,列印回車符後結束程式。

#include<stdio.h>
typedef struct {
  char data;
  int w,l,r,p;
}node;
typedef struct{
 char cd[50];
 int start;
}code;
int create (node *h){
  int i,k,n,m1,m2,p1,p2;
  printf("請輸入元素個數為:");
  scanf("%d",&n);
  for(i=1;i<n+1;i++){
    getchar();
    printf("第%d個元素的節點值和權重:",i);
    scanf("%c %d",&h[i].data,&h[i].w);
  }
  for(i=1;i<=2*n-1;i++)
      h[i].p=h[i].l=h[i].r=0;
  for(i=n+1;i<=2*n-1;i++){
      m1=m2=32767;
      p1=p2=i;
      for(k=1;k<i;k++){
          if(h[k].p==0){
              if(h[k].w<m1){
                 m2=m1;
                 p2=p1;
                 m1=h[k].w;
                 p1=k;
              }
              else if(h[k].w<m2){
                  m2=h[k].w ;
                  p2=k;
              }
          }
      }
      h[p1].p=i;
      h[p2].p=i;
      h[i].w=m1+m2;
      h[i].l=p1;
      h[i].r=p2;
  }
  printf("success for hufftree!\n");
  return n;
}
void encoding(node h[],code co[],int n){
     code d;
     int i,k,f,c;
     for(i=1;i<n+1;i++){
         d.start=n+1;
         c=i;
         f=h[i].p;
         while(f!=0){
             if(h[f].l==c)
                  d.cd[--d.start]='0';
              else  d.cd[--d.start]='1';
              c=f;
              f=h[f].p;
             
         }
         co[i]=d;
     }
     printf("輸出哈夫曼編碼:\n");
     for(i=1;i<=n;i++){
         printf("%c:",h[i].data);
         for(k=co[i].start;k<=n;k++){
             printf("%c",co[i].cd[k]);
         }
         printf("\n");
     }
}
void decoding(node h[],code co[],int n){
   int f,m,k;
   char c,ch[200];
   printf("請輸出電文(0或1),以‘#’為結束標誌:\n");
   c=getchar();
   k=1;
   while(c!='#'){
      ch[k]=c;
      c=getchar();
      k++;
   }
   m=k;
   f=2*n-1;
   k=1;
   printf("輸出哈夫曼編碼:\n");
   while(k<m){
       while(h[f].l!=0){
           if(ch[k]=='0') f=h[f].l;
           if(ch[k]=='1') f=h[f].r;
           k++;
       }
       printf("%c",h[f].data);
       f=2*n-1;
   }
   printf("\n");
}
int main(){
    int flag=5,c;
    while(flag){
          printf("\n****************************電文的編碼和譯碼********************\n");
          printf("\n**********1,建立哈夫曼樹   2,編碼   3,譯碼     0,退出系統 ****\n");
          printf("\n*提示:先建立哈夫曼樹,之後才能進行編碼或譯碼*\n");
          printf("\n-------------------------------------------------------------------\n");
          scanf("%d",&flag);
          if(flag==1){
               node h[200];
               code co[100];
               int n; //節點數
                 n=create(h);
               scanf("%d",&c);
               while(c){
                 if(c==2){
                    encoding(h,co,n);
                 }
                  if(c==3){
                    decoding(h,co,n);
                 }
                  if(c==0) { 
                     printf("退出系統。\n");
                  break;
                  }
                 scanf("%d",&c);
               }
          }
          else if(flag==0){
                printf("退出系統。\n");
                break;
          }
          else{
              printf("輸入錯誤,請重新輸入!\n");
          }
    }

    return 0;
}