哈夫曼編/譯碼系統的設計與實現

問題描述

利用哈夫曼編碼進行通信可以大大提高信道利用率,縮短信息傳輸時間,降低傳輸成本。但是,這要求在發送端通過一個編碼系統對待傳數據預先編碼,在接收端將傳來的數據進行譯碼(解碼)。對於雙工信道(即可以雙向傳輸信息的信道),每端都需要一個完整的編/譯碼系統。試爲這樣的信息收發站設計一個哈夫曼編譯碼系統。

基本要求

  1. 初始化(Initialzation)。從數據文件DataFile.data中讀入字符及每個字符的權值,建立哈夫曼樹HuffTree;
  2. 編碼(EnCoding)。用已建好的哈夫曼樹,對文件ToBeTran.data中的文本進行編碼形成報文,將報文寫在文件Code.txt中
  3. 譯碼(Decoding)。利用已建好的哈夫曼樹,對文件CodeFile.data中的代碼進行解碼形成原文,結果存入文件Textfile.txt中
  4. 輸出(Output)。輸出DataFile.data中出現的字符以及各字符出現的頻度(或概率);輸出ToBeTran.data及其報文Code.txt;輸出CodeFile.data及其原文Textfile.txt

大致過程

  1. 首先需要寫好哈夫曼樹的建立和編碼過程
  2. 其次對於譯碼,則可以從文件中一次讀取一個單詞,然後挨個完成譯碼。分別輸出到文件。
  3. 對於解碼,一次讀一個單詞的哈夫曼碼,依次和之前編好的哈夫曼碼進行匹配,直到全部解碼完成

    數據結構

哈夫曼樹節點

typedef struct {
    int weight;
    int parent,lchild,rchild;
}HufNode;

初始節點

typedef struct {
    int weight;
    char data;
    char code[maxn];//需要被建樹的信息
}HufCode;

程序模塊

(1) 初始化輸入數據

void Init(HufCode h[])//初始化輸入數據
{
    FILE *f1=fopen("DataFile.data","r");
    for(int i=0;i<alphanumber;++i)
        fscanf(f1,"%c%d ",&h[i].data,&h[i].weight);

    fclose(f1);
}

(2) 根據數據建立哈夫曼樹及將編碼保存

void HuffmanTree(HufCode *h2,HufNode *h1,int n)
{
    char str[maxn];
    int m=2*n-1;
    for(int i=0;i<m;++i){
        if(i<n)//前n個全部是葉子節點,
            h1[i].weight=h2[i].weight;
        else//後面的是還沒建成的樹
            h1[i].weight==0;
        h1[i].lchild=h1[i].parent=h1[i].rchild=0;
    }
    int s1,s2;
    for(int i=n;i<m;++i){
        select(h1,i,s1,s2);
        h1[s1].parent=i;//建立二叉樹
        h1[s2].parent=i;
        h1[i].lchild=s1;
        h1[i].rchild=s2;
        h1[i].weight=h1[s1].weight+h1[s2].weight;
    }
    str[n]='\0';
    int l;
    for(int i=0;i<n;++i){//從每個葉子節點開始倒序遍歷
        l=n-1;//倒序賦值字符串
        for(int k=i,p=h1[k].parent;p;k=p,p=h1[k].parent){//沿着葉子回溯到根節點
            if(k==h1[p].lchild)
                str[l]='0';
            else
                str[l]='1';
            l--;
        }
        strcpy(h2[i].code,str+l+1);
       // printf("%c %s\n",h2[i].data,h2[i].code);
    }
}

(3) 根節點中選擇兩個最小的根

void select(HufNode *h,int k,int &s1,int &s2)//選擇兩個最小的值
{
    int i;
    for(i=0; i<k && h[i].parent != 0; ++i);//選擇一個父節點爲0的根節點
        s1 = i;
    for(i=0; i<k; ++i){
        if(h[i].parent==0 && h[i].weight<h[s1].weight)
              s1 = i;
    }
    for(i=0; i<k; ++i){
        if(h[i].parent==0 && i!=s1)
            break;
    }
    s2 = i;
    for(i=0; i<k; ++i){
        if(h[i].parent==0 && i!=s1 && h[i].weight<h[s2].weight)
            s2 = i;
    }
}

(4) 編碼

void EnCodeing(HufCode hc[])
{
    FILE *f1=fopen("ToBeTran.data","r");
    FILE *f2=fopen("Code.txt","w");
    char str[maxn];
    while(fscanf(f1,"%s",str)!=EOF)
    {
        int len=strlen(str);
        for(int i=0;i<len;++i){
            int x=str[i]-'a';
            fprintf(f2,"%s",hc[x].code);
        }
        fprintf(f2," ");
    }
    fclose(f1);
    fclose(f2);
}

(5) 解碼

int Search(HufCode hc[],char *str)
{
    for(int i=0;i<alphanumber;++i)
        if(strcmp(hc[i].code,str)==0)
            return  i;
    return -1;
}
void DeCodeing(HufCode hc[])
{
    FILE *f1=fopen("CodeFile.data","r");
    FILE *f2=fopen("Textfile.txt","w");
    char str[maxn];
    while(fscanf(f1,"%s",str)!=EOF)
    {
        char a[maxn];
        memset(a,'\0',sizeof(a));
        int len=strlen(str),k=0;
        for(int i=0;i<len;++i){
            a[k]=str[i];
            a[k+1]='\0';
            int ans=Search(hc,a);
            if(ans!=-1){
                fprintf(f2,"%c",ans+'a');
                k=0;
                continue;
            }
            k++;
        }
        fprintf(f2," ");
    }

    fclose(f1);
    fclose(f2);
}

(6) 輸出結果

void OutPut()
{
    FILE *infile=fopen("DataFile.data","r");
    FILE *outfile=fopen("Code.txt","r");
    int w;
    char c;
    printf("各個字母及其權值\n");
    for(int i=0;i<alphanumber;++i){
        fscanf(infile,"%c %d ",&c,&w);
        printf("%c %d ",c,w);
    }

    infile=fopen("ToBeTran.data","r");
    printf("\n\n待編碼的內容:\n");
    char str[maxn];
    while(fscanf(infile,"%s",str)!=EOF)
        printf("%s ",str);

    printf("\n編碼後結果:\n");
    while(fscanf(outfile,"%s",str)!=EOF)
        printf("%s ",str);

    printf("\n\n待解碼內容:\n");
    infile=fopen("CodeFile.data","r");
    while(fscanf(infile,"%s",str)!=EOF)
        printf("%s ",str);

    printf("\n解碼結果:\n");
    outfile=fopen("Textfile.txt","r");
    while(fscanf(outfile,"%s",str)!=EOF)
        printf("%s ",str);
    printf("\n");

    fclose(infile);
    fclose(outfile);
}

全部程序

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000;
const int alphanumber=26;
typedef struct {
    int weight;
    int parent,lchild,rchild;
}HufNode;//HuffmanTree的基本定義
typedef struct {
    int weight;
    char data;
    char code[maxn];//需要被建樹的信息
}HufCode;
void Init(HufCode h[])//初始化輸入數據
{
    FILE *f1=fopen("DataFile.data","r");
    for(int i=0;i<alphanumber;++i)
        fscanf(f1,"%c%d ",&h[i].data,&h[i].weight);

    fclose(f1);
}
void select(HufNode *h,int k,int &s1,int &s2)//選擇兩個最小的值
{
    int i;
    for(i=0; i<k && h[i].parent != 0; ++i);//選擇一個父節點爲0的根節點
        s1 = i;
    for(i=0; i<k; ++i){
        if(h[i].parent==0 && h[i].weight<h[s1].weight)
              s1 = i;
    }
    for(i=0; i<k; ++i){
        if(h[i].parent==0 && i!=s1)
            break;
    }
    s2 = i;
    for(i=0; i<k; ++i){
        if(h[i].parent==0 && i!=s1 && h[i].weight<h[s2].weight)
            s2 = i;
    }
}
void HuffmanTree(HufCode *h2,HufNode *h1,int n)
{
    char str[maxn];
    int m=2*n-1;
    for(int i=0;i<m;++i){
        if(i<n)//前n個全部是葉子節點,
            h1[i].weight=h2[i].weight;
        else//後面的是還沒建成的樹
            h1[i].weight==0;
        h1[i].lchild=h1[i].parent=h1[i].rchild=0;
    }
    int s1,s2;
    for(int i=n;i<m;++i){
        select(h1,i,s1,s2);
        h1[s1].parent=i;//建立二叉樹
        h1[s2].parent=i;
        h1[i].lchild=s1;
        h1[i].rchild=s2;
        h1[i].weight=h1[s1].weight+h1[s2].weight;
    }
    str[n]='\0';
    int l;
    for(int i=0;i<n;++i){//從每個葉子節點開始倒序遍歷
        l=n-1;//倒序賦值字符串
        for(int k=i,p=h1[k].parent;p;k=p,p=h1[k].parent){//沿着葉子回溯到根節點
            if(k==h1[p].lchild)
                str[l]='0';
            else
                str[l]='1';
            l--;
        }
        strcpy(h2[i].code,str+l+1);
       // printf("%c %s\n",h2[i].data,h2[i].code);
    }
}
void EnCodeing(HufCode hc[])
{
    FILE *f1=fopen("ToBeTran.data","r");
    FILE *f2=fopen("Code.txt","w");
    char str[maxn];
    while(fscanf(f1,"%s",str)!=EOF)
    {
        int len=strlen(str);
        for(int i=0;i<len;++i){
            int x=str[i]-'a';
            fprintf(f2,"%s",hc[x].code);
        }
        fprintf(f2," ");
    }
    fclose(f1);
    fclose(f2);
}
int Search(HufCode hc[],char *str)
{
    for(int i=0;i<alphanumber;++i)
        if(strcmp(hc[i].code,str)==0)
            return  i;
    return -1;
}
void DeCodeing(HufCode hc[])
{
    FILE *f1=fopen("CodeFile.data","r");
    FILE *f2=fopen("Textfile.txt","w");
    char str[maxn];
    while(fscanf(f1,"%s",str)!=EOF)
    {
        char a[maxn];
        memset(a,'\0',sizeof(a));
        int len=strlen(str),k=0;
        for(int i=0;i<len;++i){
            a[k]=str[i];
            a[k+1]='\0';
            int ans=Search(hc,a);
            if(ans!=-1){
                fprintf(f2,"%c",ans+'a');
                k=0;
                continue;
            }
            k++;
        }
        fprintf(f2," ");
    }

    fclose(f1);
    fclose(f2);
}
void OutPut()
{
    FILE *infile=fopen("DataFile.data","r");
    FILE *outfile=fopen("Code.txt","r");
    int w;
    char c;
    printf("各個字母及其權值\n");
    for(int i=0;i<alphanumber;++i){
        fscanf(infile,"%c %d ",&c,&w);
        printf("%c %d ",c,w);
    }

    infile=fopen("ToBeTran.data","r");
    printf("\n\n待編碼的內容:\n");
    char str[maxn];
    while(fscanf(infile,"%s",str)!=EOF)
        printf("%s ",str);

    printf("\n編碼後結果:\n");
    while(fscanf(outfile,"%s",str)!=EOF)
        printf("%s ",str);

    printf("\n\n待解碼內容:\n");
    infile=fopen("CodeFile.data","r");
    while(fscanf(infile,"%s",str)!=EOF)
        printf("%s ",str);

    printf("\n解碼結果:\n");
    outfile=fopen("Textfile.txt","r");
    while(fscanf(outfile,"%s",str)!=EOF)
        printf("%s ",str);
    printf("\n");

    fclose(infile);
    fclose(outfile);
}
int main()
{
    HufCode hc[maxn];
    HufNode tree[maxn];
    Init(hc);//初始化
    HuffmanTree(hc,tree,alphanumber);//建樹
    EnCodeing(hc);//編碼
    DeCodeing(hc);//解碼
    OutPut();//輸出結果
    return 0;
}
發佈了113 篇原創文章 · 獲贊 27 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章