数据结构实验课题:基于哈夫曼树的数据压缩算法

#include<bits/stdc++.h>
#define Line cout<<"------------------------------------------\n"
#define MAX 1000
using namespace std;
typedef struct{
    int weight;
    int parent,lchild,rchild;
}*HuffmanTree,HTNode;

string str,huffmancode1,huffmancode2,dehuffmancode1,dehuffmancode2;///分别为原字符串,新编码,原编码,新编码解码,原编码解码
int y;

void menu()
{
    cout<<" **************************************\n\n";
    cout<<"   实验:基于哈夫曼树的数据压缩算法:\n\n";
    cout<<"    1.输入字符串构造哈夫曼树\n";
    cout<<"    2.统计字符出现频率\n";
    cout<<"    3.输出哈夫曼树的存储结构终态\n";
    cout<<"    4.输出每个字符的哈夫曼编码\n";
    cout<<"    5.输出原字符串编码\n";
    cout<<"    6.输出原编码解码\n";
    cout<<"    7.输入二进制编码进行解码\n";
    cout<<"    0.退出\n\n";
    cout<<" **************************************\n\n";
}
void Countnum(string s,int &k,pair<char,int>ch[])///统计字符出现频率,用pair数组ch存储
{
    int num=1;
    sort(s.begin(),s.end());
    for(int i=0;i<s.size();i++){
        if(s[i]!=s[i+1]){
            ch[++k]=make_pair(s[i],num);
            num=1;
        }
        else num++;
    }
}
void Select(HuffmanTree HT,int t,int &s1,int &s2)/// 从当前森林中选择双亲为0且权值最小的两个树根结点s1和s2
{
    int MIN1=0x3f3f3f3f,MIN2=0x3f3f3f3f;//MIN1最小值,MIN2次小值
    for(int i=1;i<=t;i++){
        if(!HT[i].parent&&HT[i].weight<MIN1){
            MIN2=MIN1;
            s2=s1;
            MIN1=HT[i].weight;
            s1=i;
        }
        else if(!HT[i].parent&&HT[i].weight<MIN2){
            MIN2=HT[i].weight;
            s2=i;
        }
    }
}
void CreatHuffmanTree(HuffmanTree &HT,int n,pair<char,int>ch[])///构造哈夫曼树
{
    if(n<=1)return;
    int m=2*n-1;
    HT=new HTNode[m+1];
    for(int i=1;i<=m;i++)
        HT[i].parent=0,HT[i].lchild=0,HT[i].rchild=0;
    for(int i=1;i<=n;i++)
        HT[i].weight=ch[i].second;

    int s1,s2;
    for(int i=n+1;i<=m;i++){
        Select(HT,i-1,s1,s2);
        HT[s1].parent=i,HT[s2].parent=i;
        HT[i].lchild=s1,HT[i].rchild=s2;
        HT[i].weight=HT[s1].weight+HT[s2].weight;
    }
}
void CreatHuffmanCode(HuffmanTree HT,char** &HC,int n,pair<char,int>ch[])///求各个字符的哈夫曼编码,数组HC存储
{
    char *cd;
    HC=new char*[n+1];
    cd=new char[n];
    cd[n-1]='\0';
    for(int i=1;i<=n;i++){
        int sta=n-1,c=i,f=HT[i].parent;
        while(f){
            --sta;//倒序存储
            if(HT[f].lchild==c)
                cd[sta]='0';
            else
                cd[sta]='1';
            c=f;f=HT[f].parent;//继续向上回溯
        }
        HC[i]=new char[n-sta];
        strcpy(HC[i],&cd[sta]);
    }
    delete cd;
}
void HuffmanCodeString(char *HC[],pair<char,int>ch[],int n,string str)///求进行哈夫曼编码后的字符串,编码字符串huffmancode存储
{
    huffmancode1="";
    for(int i=0;i<str.size();i++){//依次遍历字符串的每个字符
        for(int j=1;j<=n;j++){
            if(str[i]==ch[j].first){//每个字符找到它对应的编码
                huffmancode1+=HC[j];
                break;
            }
        }
    }
}
void Dehuffmancode1(HuffmanTree HT,int n,pair<char,int>ch[])///求对编码进行解码后的字符串,解码字符串dehuffmancode1存储
{
    dehuffmancode1="";
    int m=2*n-1;
    int k=m;
    for(int i=0;i<huffmancode1.size();i++){
        if(huffmancode1[i]=='0')//0找左儿子
            k=HT[k].lchild;
        else if(huffmancode1[i]=='1')//1找右儿子
            k=HT[k].rchild;
        if(k<=n){
            dehuffmancode1+=ch[k].first;
            k=m;//重新从根开始
        }
    }
}
bool Dehuffmancode2(HuffmanTree HT,int n,pair<char,int>ch[])///输入二进制编码后根据已有的哈夫曼树解码
{
    cout<<"请输入一个二进制编码:";
    cin>>huffmancode1;
    for(int i=0;i<huffmancode1.size();i++){
        if(huffmancode1[i]!='0'&&huffmancode1[i]!='1'){
            cout<<"该二进制编码不符合标准!\n";
            return false;
        }
    }
    Dehuffmancode1(HT,n,ch);
    return true;
}
void Inputstring(int &n,HuffmanTree &HT,char** &HC,pair<char,int>ch[])///输入字符串并构造哈夫曼树
{
    system("cls");
    menu();Line;
    cout<<"请输入一个字符串:";
    getchar();///吸收输入指令1按下回车的换行符
    getline(cin,str);
    Countnum(str,n,ch);
    if(n==1){
        y=0;
        cout<<"\n该字符串无法构造哈夫曼树,请重新输入!\n";
        return;
    }
    CreatHuffmanTree(HT,n,ch);
    CreatHuffmanCode(HT,HC,n,ch);
    HuffmanCodeString(HC,ch,n,str);
    huffmancode2="";
    huffmancode2=huffmancode1;
    Dehuffmancode1(HT,n,ch);
    dehuffmancode2="";
    dehuffmancode2=dehuffmancode1;
    cout<<"\n构造哈夫曼树成功!\n";y=1;
}
int main()
{
    menu();
    HuffmanTree HT;
    char **HC;
    int choose=-1,n;
    pair<char,int>ch[MAX];
    while(choose){
        cout<<"\n请输入指令:";
        cin>>choose;
        if(!y&&choose!=1&&choose!=0){
            cout<<endl;Line;
            cout<<"请先执行指令1,输入一个字符串!\n";Line;
            continue;
        }
        cout<<endl;Line;
        switch(choose){

            case 0: cout<<"退出成功!\n";Line;break;

            case 1: n=0;memset(ch,0,sizeof(ch));
                    Inputstring(n,HT,HC,ch);
                    Line;break;

            case 2: cout<<"各字符出现的频率为:";
                    for(int i=1;i<=n;i++)
                        cout<<ch[i].first<<":"<<ch[i].second<<' ';
                    cout<<endl;Line;break;

            case 3: cout<<"哈夫曼树的存储结构的终态为:\n";
                    cout<<"结点i"<<' '<<"weight"<<' '<<" parent"<<' '<<"lchild"<<' '<<" rchild\n";
                    for(int i=1;i<=2*n-1;i++)
                        cout<<setw(3)<<i<<'\t'<<HT[i].weight<<'\t'<<HT[i].parent<<'\t'<<HT[i].lchild<<'\t'<<HT[i].rchild<<endl;
                    Line;break;

            case 4: cout<<"各个字符的哈夫曼编码为:";
                    for(int i=1;i<=n;i++)
                        cout<<ch[i].first<<":"<<HC[i]<<' ';
                    cout<<endl;
                    Line;break;

            case 5: cout<<"原编码字符串为:"<<huffmancode2<<"\n";
                    Line;break;

            case 6: cout<<"原解码字符串为:"<<dehuffmancode2<<endl;
                    Line;break;

            case 7: if(Dehuffmancode2(HT,n,ch))
                        cout<<"该编码进行解码后的字符串为:"<<dehuffmancode1<<endl;
                    Line;break;

            default:cout<<"指令不存在,请重新输入!\n";
                    Line;break;
        }
    }
    return 0;
}

综合实验: 1. 问题描述 利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。这要求在发送端通过一个编码系统对待传输数据预先编码,在接收端将传来的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的信息收发站编写一个哈夫曼码的编/译码系统。 2. 基本要求 一个完整的系统应具有以下功能: (1) I:初始化(Initialization)。从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。 (2) E:编码(Encoding)。利用已建好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。 (3) D:译码(Decoding)。利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件Textfile中。 (4) P:印代码文件(Print)。将文件CodeFile以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件CodePrin中。 (5) T:印哈夫曼树(Tree printing)。将已在内存中的哈夫曼树以直观的方式(比如树)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint 中。 3. 测试数据 用下表给出的字符集和频度的实际统计数据建立哈夫曼树,并实现以下报文的编码和译码:“THIS PROGRAME IS MY FAVORITE”。 字符 A B C D E F G H I J K L M 频度 186 64 13 22 32 103 21 15 47 57 1 5 32 20 字符 N O P Q R S T U V W X Y Z 频度 57 63 15 1 48 51 80 23 8 18 1 16 1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值