數據結構課程設計:3、哈夫曼編碼/譯碼系統(樹應用)

                                               哈夫曼編碼/譯碼系統(樹應用)

[問題描述]

 

利用哈夫曼編碼進行通信,可以壓縮通信的數據量,提高傳輸效率,縮短信息的傳輸時間,還有一定的保密性。現在要求編寫一程序模擬傳輸過程,實現在發送前將要發送的字符信息進行編碼,然後進行發送,接收後將傳來的數據進行譯碼,即將信息還原成發送前的字符信息。

 

[實現提示]

 

在本例中設置發送者和接受者兩個功能,

發送者的功能包括:

①輸入待傳送的字符信息;

②統計字符信息中出現的字符種類數和各字符出現的次數(頻率);

②根據字符的種類數和各自出現的次數建立哈夫曼樹;

③利用以上哈夫曼樹求出各字符的哈夫曼編碼;

④將字符信息轉換成對應的編碼信息進行傳送。

接受者的功能包括:

①接收發送者傳送來的編碼信息;

②利用上述哈夫曼樹對編碼信息進行翻譯,即將編碼信息還原成發送前的字符信息。

從以上分析可發現,在本例中的主要算法有三個:

(1)哈夫曼樹的建立;

(2)哈夫曼編碼的生成;

(3)對編碼信息的翻譯。

 

[設計思路]

 

  1. 哈夫曼樹的建立
  2. 哈夫曼編碼的生成
  3. 對編碼信息的翻譯

[代碼及註釋]

#include<iostream>
#include<map>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXSIZE 111                                       /*可傳遞信息的最大長度*/
//結構
typedef struct{
    int weight;                                           /*結點的權值*/
    int parent,lchild,rchild;                             /*結點的雙親、左孩子、右孩子的下標*/
    char ch;                                              /*結點的字符*/
    string HuffmanCode;                                   /*結點的哈夫曼編碼*/
}HTNode,*HuffmanTree;                                     /*動態分配數組儲存哈夫曼樹*/
map<char,int> Map;                                        /*map容器儲存字符及對應次數*/
//子函數
void GetInformation(int &kind);                           /*統計字符種類數和各字符出現的次數*/
void SelectMinNode(HuffmanTree &HT,int k,int &s1,int &s2);/*選擇兩個權值最小結點*/
bool CreatHuffmanTree(HuffmanTree &HT,int n);             /*哈夫曼樹的創建*/
void CreatHuffmanCode(HuffmanTree &HT,int n);             /*哈夫曼編碼的創建*/
void Translate(HuffmanTree HT,int n);                     /*譯碼*/
//具體內容
void GetInformation(int &kind)
{
    kind=0;
    cout<<"輸入傳遞信息(不含中文):";
    char str[MAXSIZE];
    gets(str);                                            /*可讀入含空格道德字符串*/
    for(int i=0;i<strlen(str);++i)
        Map[str[i]]++;                                    /*記錄字符出現次數*/
    map<char,int> ::iterator it=Map.begin();
    while(it!=Map.end())
    {
        ++kind;
        it++;
    }                                                     /*迭代器遍歷*/
    cout<<endl;
    cout<<"字符種類:"<<kind<<endl<<endl;
    cout<<" ---------"<<endl;
    cout<<"|字符"<<" 次數"<<endl;
    for(it=Map.begin();it!=Map.end();++it)
            cout<<"| "<<(*it).first<<"    "<<(*it).second<<endl;
    cout<<" ---------"<<endl;
}
void SelectMinNode(HuffmanTree &HT,int k,int &s1,int &s2)
{
    int Min=1e9;                                          /*初始化當前最小權值*/
    for(int i=1;i<=k;++i)
        if(!HT[i].parent)
            if(HT[i].weight<=Min)
            {
                Min=HT[i].weight;                         /*不斷更新Min*/
                s1=i;
            }                                             /*從前k個結點找出最小結點*/
    Min=1e9;                                              /*重置權值*/
    for(int i=1;i<=k;++i)
        if(!HT[i].parent&&i!=s1)
            if(HT[i].weight<=Min)
            {
                Min=HT[i].weight;                         /*不斷更新Min*/
                s2=i;
            }                                             /*從前k個結點除s1外找出最小結點*/
}
bool CreatHuffmanTree(HuffmanTree &HT,int n)
{
    if(n<=1)
    {
        cout<<"<<<<字符種類太少無需使用哈夫曼樹"<<endl;
        return false;
    }
    else
    {
        int m=2*n-1;
        HT=new HTNode[m+1];                                 /*分配空間,0號單元未使用*/
        map<char,int> ::iterator it=Map.begin();
        int j=0;
        while(it!=Map.end())
        {
            ++j;
            HT[j].weight=(*it).second;                      /*初始化字符出現次數*/
            HT[j].ch=(*it).first;                           /*初始化字符*/
            HT[j].HuffmanCode="";                           /*初始化哈夫曼編碼爲空*/
            HT[j].lchild=HT[j].rchild=HT[j].parent=0;       /*左右孩子及雙親均初始化爲0*/
            ++it;
        }
        for(int i=n+1;i<=m;++i)
            HT[i].weight=HT[i].parent=HT[i].rchild=HT[i].lchild=0;
                                                            /*初始化從n+1到m的結點*/
        for(int i=n+1;i<=m;++i)                             /*n-1次的選擇刪除合併來創建哈夫曼樹*/
        {
            int s1,s2;
            SelectMinNode(HT,i-1,s1,s2);                    /*將最小兩個結點的下標賦予s1,s2;*/
            HT[s1].parent=i;                                /*s1雙親親賦予i第i編號*/
            HT[s2].parent=i;                                /*s2雙親親賦予i第i編號*/
            HT[i].lchild=s1;                                /*s1成爲編號爲i的左孩子*/
            HT[i].rchild=s2;                                /*s2成爲編號爲i的右孩子*/
            HT[i].weight=HT[s1].weight+HT[s2].weight;       /*合併左右孩子權值*/
        }
        cout<<"<<<<哈夫曼樹創建成功"<<endl<<endl;
        return true;
    }
}
void CreatHuffmanCode(HuffmanTree &HT,int n)
{
	int c,f;
	cout<<"<<<<哈夫曼編碼創建成功,如下:"<<endl;
	for(int i=1;i<=n;i++)
	{
        c=i;                                                /*c:當前結點序號*/
        f=HT[i].parent;                                     /*f:當前節點的雙親*/
		while(f!=0)                                         /*f爲根節點終止*/
		{
            if(HT[f].lchild==c)HT[i].HuffmanCode+="0";      /*左邊加0*/
            else HT[i].HuffmanCode+="1";                    /*右邊加1*/
            c=f;
            f=HT[f].parent;
                                                            /*不斷向上層查找*/
        }
    reverse(HT[i].HuffmanCode.begin(),HT[i].HuffmanCode.end());
                                                            /*翻轉,因爲上步操作得到的是逆序*/
	cout<<HT[i].ch<<":"<<HT[i].HuffmanCode<<endl;
	}
	cout<<endl;
}
void Translate(HuffmanTree HT,int n)
{
    cout<<"輸入譯碼:";
    string str;
    cin>>str;
    int len=str.size();
    int flag=-1;                                            /*判斷譯碼是否成功的標誌*/
    string ans,temp;                                        /*ans:最終譯碼答案*/
                                                            /*temp:匹配臨時字符串*/
    for(int i=0;i<len;++i)
    {
        temp+=str[i];
        for(int j=1;j<=n;++j)
            if(HT[j].HuffmanCode==temp)
            {
                temp="";                                    /*匹配成功將臨時字符串置空*/
                ans+=HT[j].ch;
                flag=i;
            }
    }
    if(flag!=len-1)cout<<"<<<<輸入的源碼有誤!!!"<<endl;     /*沒有匹配成功*/
    else
    {   cout<<"<<<<譯碼成功!內容如下"<<endl;
        cout<<ans<<endl;
    }
    cout<<"是否繼續(y/n)?";
    char judge;                                             /*判斷是否繼續譯碼*/
    cin>>judge;
    if(judge=='y')Translate(HT,n);
    else return;
}
int main()
{
    HuffmanTree HT;
    int kind;
    GetInformation(kind);
    if(CreatHuffmanTree(HT,kind))
    {
        CreatHuffmanCode(HT,kind);
        Translate(HT,kind);
    }

    return 0;
}

[簡單展示]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章