基于哈夫曼(Huffmen)编码的通信系统的设计与实现

利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对待传输数据预先编码,在接收端将传来的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的信息收发站写一个哈夫曼的编/译码系统。
【基本要求】
一个完整的系统应具有以下功能:
(1)I:初始化(Initialization)。从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。
(2)E:编码(Encoding)。利用以建好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
(3)D:译码(Decoding)。利用已经建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。
(4)P:打印代码文件(Print)。将文件CodeFile以紧凑格式显示在终端上,每行50个代码,同时将此字符形式的编码写入文件CodePrint中。
(5)T:打印哈夫曼树(Tree printing)。将已经在内存中的哈夫曼树以直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。
【测试数据】
(1)利用教科书例6-2中的数据调试程序。
(2)用下表给出的字符集和频度的实际统计数据建立哈夫曼树,并实现以下报文的编码和译码:“THIS PROGRAM 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

【实现提示】
(1)编码结果以文本式存储在文件CodeFile中。
(2)用户界面可以设计为“菜单”方式:显示上述功能符号,再加上“Q”,表示退出运行Quit。请用户键入一个选择功能符。此功能执行完毕后再显示此菜单,直至某次用户选择了“Q”为止。
(3)在程序的一次执行过程中,第一次执行I,D或C命令之后,哈夫曼树已经在内存了,不必再读入。每次执行中不一定执行I命令,因为文件hfmTree可能早已建好。

大致浏览题目后,可以发现:
该实验有以下几个难点:
1.文件的读取和写入
2.空格的输入
3.解码(操作D)的算法较为复杂
4.解除各操作之间的关联性
这也是我做这道实验题目时卡住我的四个难点。

I(Initialization)操作
注意读入空格时应灵活处理,C++中可以读取含有空格的字符串(cin.getline),而单独读取空格并紧接着读取其他的数据是较难实现的,因此不妨先一次性输入所有的字符(以字符串存储),再利用for循环输入权值等信息。最后就是常规的哈夫曼树数组建立法,但还要记得要计算各叶子结点到根结点的长度(因为后面的Encoding操作用到了这一个数据项)。
文件的写入也需要灵活的处理,一行读取不同类型的数据项是很难实现的(若E、D等操作出现在I之前,需要从该文件读取现成的哈夫曼树),因此不妨先将各同类型的数据写到一行上(并以空格相间隔),操作I也就实现了。

int Initialization(H_Tree *Tree){
   
    int n;
    cin>>n;
    for(int i = 0; i < 2*n-1;i ++){
   
        Tree[i].lchild=-1;
        Tree[i].rchild=-1;
        Tree[i].parent=-1;
    }//init tree
    char s[100];
    getchar();
    cin.getline(s,100);
    for(int i = 0;i < n; i ++){
   
        Tree[i].data=s[i];//input letter
        cin>>Tree[i].weigth;//input weight
    }//input data
    for(int i = 0 ; i <n-1; i ++){
   
        int min1,min2;
        for(int j=0;j<n+i;j++){
   
            if(Tree[j].parent==-1){
   
                min1=j;
                break;
            }
        }
        for(int j=0;j<n+i;j++){
   
            if(Tree[j].weigth<Tree[min1].weigth&&Tree[j].parent==-1)
                min1=j;
        }
        Tree[n+i].lchild=min1;
        Tree[min1].parent=n+i;
        for(int j=0;j<n+i;j++){
   
            if(Tree[j].parent==-1){
   
                min2=j;
                break;
            }
        }
        for(int j=0;j<n+i;j++){
   
            if(Tree[j].weigth<Tree[min2].weigth&&Tree[j].parent==-1)
                min2=j;
        }
        Tree[n+i].rchild=min2;
        Tree[min2].parent=n+i;
        Tree[n+i].weigth=Tree[min1].weigth+Tree[min2].weigth;
    }
    for(int i  = 0; i < n  ; i ++){
   
        int temp=i;
        int length=0;
        while(temp!=-1){
   
            temp=Tree[temp].parent;
            length++;
        }
        Tree[i].length=length;}
    FILE *hfmTree;//put tree into file named hfmTree
    hfmTree=fopen("hfmTree.txt","w+");;
    for(int i = 0;i < n;i ++){
   
        fprintf(hfmTree,"%c",Tree[i].data);
    }
    fputc('\n',hfmTree);
    for(int i = 0;i < 2*n-1;i ++){
   
        fprintf(hfmTree,"%d ",Tree[i].weigth);
    }
    fputc('\n'
  • 5
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值