文章目录

  • (一)设计描述
  • (二)需求分析
  • (三)详细设计
  • (四)代码实现与测试
  • (五)个人总结

(一)设计描述

1.题目描述
设计一个利用哈夫曼算法的编码和译码系统,重复地显示并处理以下项目,直到选择退出为止。

1) 输入一串字符,然后统计其中各个字符的个数,即每个字符的权值。
2)  进行初始化操作,并建立哈夫曼树;
3)  编码:利用建好的哈夫曼树生成哈夫曼编码,并输出编码;
4)  译码,即输入每个字符对应的二进制的编码(0或1),然后输出对应的字符。
5) 结束操作。

2.设计目的与要求

1)目的:

通过布置具有一定难度的实际程序设计项目,进一步理解和掌握课堂上所学各种基本抽象数据类型的逻辑结构、存储结构和操作实现算法

2)要求:

1.要求利用C\C++语言来完成系统的设计;
2.突出C语言的函数特征(以多个函数实现每一个子功能)或者C++语言面向对象的编程思想;
3.画出功能模块图;
4.进行简单界面设计,能够实现友好的交互;
5.具有清晰的程序流程图和数据结构的详细定义;
6.熟练掌握C语言或者C++语言的各种操作。

(二)需求分析

第一步 定义Treecount(哈夫曼树节点的个数),随后定义两个结构体,HTnode和HTcode,结构体HTnode储存数据信息,即(输入的字符(data),权值(weight),父结点(parent),左孩子(lchild),右孩子(rchild))。 结构体HTnode储存结果信息,即(输入的字符(data),BT数组(储存哈夫曼编码结果),start(哈夫曼编码的起始位置),num统计各个字符的出现的个数,即权值,input 输入的字符)
第二步 定义字符指针P,数组letter[]和数组string[],数组letter用来调用数据 input,data,num;string[]用来输入字符,同时让指针P指向string[];由于数组是单个存储,判断字符是否相同,用account,num分别统计字母个数以及每个字符的对应次数,即求权值。
第三步 首先定义两个数组huffnode,array[]分别储存结点与字符,然后进行哈夫曼树的初始化,然后找到权值最小的两个结点,并记录当前下标。由于是逆序输出,左右子树的结点位置为2n-1;得知左右子树的权值后,让左右子树权值进行相加,把值赋给一个新的结点。
第四步 结构体HTcode实例化一个对象begin,并定义两个数组huffnode,huffcode,调用哈夫曼树,并记录编码的位置为n-1;倒序编码,并记录下标。然后回溯头结点,找到左孩子,赋值为0;找到右孩子赋值为1。然后进行start–,倒着计算编码,沿着父母结点往上走到结点,保存并求出每个叶子节点的哈夫曼编码与编码的起始位。
第五步 定义数组code数组,字符指针q,输入0和1的数字组合,此时哈夫曼树对应的叶子结点下标为2n-2;然后进行译码,如果读到0,从根结点的左孩子继续读入,直到读到1,然后继续读入,即读到了一个叶子(字符),即翻译一个字符成功,然后进行遍历输出结果。
第六步 用户选择结束系统

(三)详细设计

1.实现思想

1.首先要构造一棵哈夫曼树,哈夫曼树的结点结构包括权值,双亲,左右孩子;假如由n个字符来构造一棵哈夫曼树,则共有结点2n-1个;在构造前,先初始化,初始化操作是把双亲,左右孩子的下标值都赋为0;然后依次输入每个结点的权值

2.第二步是通过n-1次循环,每次先找输入的权值中最小的两个结点,把这两个结点的权值相加赋给一个新结点,,并且这个新结点的左孩子是权值最小的结点,右孩子是权值第二小的结点;鉴于上述找到的结点都是双亲为0的结点,为了下次能正确寻找到剩下结点中权值 最小的两个结点,每次循环要把找的权值最小的两个结点的双亲赋值不为0(i).就这样通过n-1循环下、操作,创建了一棵哈夫曼树,其中,前n个结点是叶子(输入的字符结点)后n-1个是度为2的结点

3.编码的思想是逆序编码,从叶子结点出发,向上回溯,如果该结点是回溯到上一个结点的左孩子,则在记录编码的数组里存“0”,否则存“1”,注意是倒着存;直到遇到根结点(结点双亲为0),每一次循环编码到根结点,把编码存在编码表中,然后开始编码下一个字符(叶子)

4.译码的思想是循环读入一串哈夫曼序列,读到“0”从根结点的左孩子继续读,读到“1”从右孩子继续,如果读到一个结点的左孩子和右孩子是否都为0,如果是说明已经读到了一个叶子(字符),翻译一个字符成功,把该叶子结点代表的字符存在一个存储翻译字符的数组中,然后继续从根结点开始读,直到读完这串哈夫曼序列,遇到结束符便退出翻译循环

3.2 创建哈夫曼树图示
已知叶子节点为{10,20,30,40},以这4个权值构建树b的过程为:




3.实现流程图

(四)代码实现与测试

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<windows.h>#define Treecount 50            //最大叶结点个数
#define MAXSIZE 500
typedef struct node {char data;int weight;int parent;int lchild;int rchild;
} HTnode;
typedef struct code {char  data;int BT[MAXSIZE];      //数组,存放字符的哈夫曼编码int start;           //该编码在数组中的开始位置char input;int num;
} HTcode;
void Createhufftree(HTnode HuffNode[],int n,HTcode array[]) {   // array[]: 用来存储字符及其权值int i,j;int minfirst,minsecond;int Lnode,Rnode;for(i=0; i<2*n-1; i++) {HuffNode[i].data=0;HuffNode[i].weight=0;HuffNode[i].parent=-1;HuffNode[i].lchild=-1;HuffNode[i].rchild=-1;}for(i=0; i<n-1; i++) {minfirst=minsecond=32767;  //给最小和次小的树赋最大值Lnode=Rnode=-1;for(j=0; j<n+i; j++) {if(HuffNode[j].parent==-1 && HuffNode[j].weight<minfirst) {    //每次找出剩下的最小权值,并将最小权值赋给次小minfirst=minsecond;Rnode=Lnode;minfirst=HuffNode[j].weight;Lnode=j;   //记录下标} else if(HuffNode[j].parent==-1 && HuffNode[j].weight<minsecond) {minsecond=HuffNode[j].weight;Rnode=j;}}HuffNode[Lnode].parent = n+i;HuffNode[Rnode].parent = n+i;HuffNode[n+i].weight = HuffNode[Lnode].weight+HuffNode[Rnode].weight;HuffNode[n+i].lchild = Lnode;HuffNode[n+i].rchild = Rnode;}for(i=0; i<n; i++) {HuffNode[i].weight=array[i].num;    //将字符个数赋给权值HuffNode[i].data=array[i].input;}
}
void QQ() {printf("请输入二进制译码启动密码,密码错误默认结束(即为默认退出):");long sercret;scanf("%d",&sercret);if(sercret==11011) {Sleep(1000);} else {Sleep(1000);printf("非法操作,结束系统");exit(-1);}
}
void  HuffmanCoding(int  n, HTcode array[]) {// array[]: 用来存储字符及其权值HTnode  HuffNode[1000];HTcode  HuffCode[Treecount];HTcode  begin;FILE *fp;fp=fopen("D:\\a.txt","w");Createhufftree(HuffNode,n,array);int  i, j ;int  loc,p;char code[30],*q;for(i=0; i<n; i++) {begin.start=n-1;                  //编码的开始位置loc=i;p=HuffNode[loc].parent;while(p!=-1) {if(HuffNode[p].lchild==loc)begin.BT[begin.start]=0;elsebegin.BT[begin.start]=1;begin.start--;                       //倒着计算编码loc=p;                               //沿着父母结点往上走到顶点p=HuffNode[loc].parent;}for(j=begin.start+1; j<n; j++)HuffCode[i].BT[j]=begin.BT[j];HuffCode[i].start=begin.start;                      //   保存求出的每个叶节点的哈夫曼编码和编码的起始位printf("\n");}printf("各个字符对应的二进制编码(1//0//1//0)如下:\n");for(i=0; i<n; ++i) {printf("字符%c的密文:",HuffNode[i].data);for(j=HuffCode[i].start + 1; j<n; j++)      //start走过了,加一恢复到开始位,编码个数小于nprintf("%d", HuffCode[i].BT[j]);printf("\n");}printf("\n");printf("编码成功,1s后打印哈夫曼编码:\n");Sleep(1000);for(i=0; i<n; ++i) {for(j=HuffCode[i].start+1; j<n; j++) {fprintf(fp,"%d",HuffCode[i].BT[j]);}for(j=HuffCode[i].start + 1; j<n; j++) {printf("%d", HuffCode[i].BT[j]);}}printf("\n\n");if(i>0) {QQ();}//   译码:system("cls");printf("            ----- ∮哈夫曼译码系统已经就绪 ∮-------        \n");printf("各字符的对应的编码如下:\n"); for(i=0; i<n; ++i) {printf("字符%c的密文:",HuffNode[i].data);for(j=HuffCode[i].start + 1; j<n; j++)      //start走过了,加一恢复到开始位,编码个数小于nprintf("%d", HuffCode[i].BT[j]);printf("\n");}printf("                  --> 请输入对应的二进制数字:              \n");scanf("%s",&code);q = code;loc = 2*n -2;                                  //    哈夫曼树的根节点下标printf("译码成功,正在打印译码结果:\n");Sleep(2000);while( *q != NULL) {if( *q== '0') {loc = i =HuffNode[loc].lchild;if(HuffNode[loc].lchild == -1 && HuffNode[loc].rchild == -1) {printf("%c",HuffNode[i].data);fprintf(fp,"%c",HuffNode[i].data);loc = 2*n - 2;}} else if(*q == '1') {loc = i = HuffNode[loc].rchild;if(HuffNode[loc].lchild == -1 && HuffNode[loc].rchild == -1) {fprintf(fp,"%c",HuffNode[i].data);printf("%c",HuffNode[i].data);loc = 2*n-2;                       // 重新从根遍历}} else {printf("非法输入!");}q++;}printf("\n");fclose(fp);
}
void menu() {system("color F");printf("                                                      ");printf("                                                     \n");printf("   ____〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓____    \n");printf("               ||  哈夫曼编码  ||                    \n");printf("        _________☆界面选择如下☆_________           \n");printf("                                                     \n");printf("             -> 1 ☆.编码与译码                      \n");printf("             -> 2 ☆.结束系统                        \n");printf("------------ ☆             ☆-----------------      \n");printf("              ∮请手动输入编号:              ");
}
void Treeaction() {HTcode letter[50];char string[1000], *p;int i, account=0;printf("          ----- ∮哈夫曼编码系统已经就绪 ∮-------        \n");printf("            》》  请输入你要编码的字符串:");scanf("%s",&string);for(i=0; i<50; i++) {letter[i].input=0;letter[i].num=0;}p=string;while(*p!=NULL) {for(i=0; i<=account+1; i++) {if(letter[i].input==NULL) {      //letter[i].input存储所有的字符,用letter[i].num存储相同的字符的数量letter[i].input=*p;letter[i].num++;account++;                       // 统计不同字符的个数break;} else if(letter[i].input==*p) {letter[i].num++;break;}}p++;}printf("\n");printf("不同的明文(字符)个数:%d\n",account);printf("\n");printf("输出输入的字符的权值\n");for(i=0; i<account; i++) {       //输出不同字符及其所对应的权值printf("当前字符%c的权值为%d",letter[i].input,letter[i].num);printf("\n");}printf("\n");HuffmanCoding(account,letter);}
int main() {int  n,flaglist=1;char choice;while(flaglist) {menu();scanf("%d",&n);switch(n) {case 1:system("cls");Treeaction();printf("\n");printf("2秒后系统进行返回!\n") ;Sleep(2000);printf("\n");system("cls");printf("已经返回!\n"); printf("请根据个人意愿进行操作!\n");printf("\n");break;case 2:exit(0);}}return 0;
}

(五)个人总结

通过这次课程设计,我收获了很多,认清了课程设计的需求,更认清了自己。谈起缺点,自己代码实现的能力也是破绽百出,对相对较难的题目不能冷静解决,经常犯一些低级的错误。然无独有偶,自己也有优点,自己思想上能理解难题,并尝试解决难题,考虑比较周到。
这次的课程设计,难度处于中等地位,但实现起来并不没有想象中的那么容易。它需要考虑多种因素,必须充分理解题目要求,化大难题为多个小难题,把具体实现步骤细分,认真完成每一步步骤,然后综合实现题目对应的问题。 时间如白驹过隙,无声滑过指尖。
学期即将完结,即将大二,不免多生感想。回想一年时光,自己虽说付出努力,然并不能收益众多。深知自己与他人之差距,然必须成为优秀者,方可日后有一席之地。

我没有科学家的那样的天赋异禀,而我却又有一颗积极向上的心,以“努力不一定成功,但不努力绝不会成功”为座右铭,付诸行动与汗水,不忘初心,厚积薄发。正如诗人王之涣所说:“欲穷千里目,更上一层楼。”要有“燕雀安知鸿鹄之志”的眼光,实现能力之飞跃,思想之迅捷,然自己必须十分努力,才能看起来毫不费力。
风雨过后才会见到彩虹。你尽管去努力,剩下的交给天命。定当不忘学习,砥砺前行。肺腑之言,溢于言表。

Huffman编码的设计与实现相关推荐

  1. 数据结构课程设计报告——Huffman编码

    目录 一. 问题描述与要求 二. 需求分析 三. 设计 3.1 设计思想 3.1.1 数据与操作的特性 3.1.2 数据结构设计 3.1.3 算法设计 3.2 设计表示 3.2.1 函数调用关系图 3 ...

  2. huffman编码的程序流程图_Huffman编码实现压缩解压缩

    这是我们的课程中布置的作业.找一些资料将作业完毕,顺便将其写到博客,以后看起来也方便. 原理介绍 什么是Huffman压缩 Huffman( 哈夫曼 ) 算法在上世纪五十年代初提出来了,它是一种无损压 ...

  3. 文件压缩 Huffman编码 (java)

    用到的知识点有: 1,二叉堆Heap的设计,实现堆排序 2,二叉树的链式构造 3,Huffman编码以及Huffman树的构建 4,二进制文件I/O流 的读写 5,比特输出流的类设计 程序目录: 1 ...

  4. 【算法】Huffman编码(数据结构+算法)

    1.描述 Huffman编码,将字符串利用C++编码输出该字符串的Huffman编码. Huffman树是一种特殊结构的二叉树,由Huffman树设计的二进制前缀编码,也称为Huffman编码在通信领 ...

  5. 贪心----多元Huffman编码问题

    多元Huffman编码问题 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 在一个操场的四周摆放着n堆石子.现要将石子有 ...

  6. HuffMan编码C语言实现

    HuffMan编码C语言实现 实现了一种编码方式,和两种解码方式. 解码一种使用的是叶子回溯根. 一种使用了从根遍历过程. 代码: HuffManEncoding // // Created by Z ...

  7. Huffman编码、Shannon编码、Fano编码——《小王子》文本压缩与解压

    一.实验要求: 1 采用熵编码对<小王子>文本进行压缩,生成压缩文件: 2 将压缩文件解压,并与源文件比较: 3 从香农编码.Huffman编码.Fano编码中选择一种: 4 计算编码效率 ...

  8. Huffman编码/译码问题

    Huffman编码/译码 问题描述 利用哈夫曼编码进行信息通讯可以大大提高信道利用率,缩短信息传输时间,降低传输成本.但是,这要求在发送端通过一个编码系统对待传数据预先编码:在接收端将传来的数据进行译 ...

  9. 数据流压缩原理实现(huffman编码,LZ77压缩算法)

    1. 压缩原理deflate算法 a) LZ77 算法原理 b) Huffman算法原理 c) Huffman算法测试实例 2.  关于zlib库的实际应用以及gzip格式分析查看下一篇 一.数据压缩 ...

最新文章

  1. Spring3 MVC
  2. python作业6月14日
  3. 接口 DataOutput
  4. 一个容易被忽视的css选择器
  5. 【HDU - 1542】Atlantis (线段树,扫描线)
  6. Error: Cannot find module ‘import-local‘
  7. android开发JNI之高级篇
  8. SpringMCV结构
  9. 运动会管理系统java
  10. redhat linux防火墙状态,Redhat下配置iptables防火墙
  11. 如何创建自己的apt软件源
  12. QQ群管机器人html官网源码
  13. 单节2A锂电池充电芯片方案,PD和QC快充充电器5-12V输入
  14. 2016年上半年系统集成中项4月6日作业
  15. 超 82% 的 GitHub 代码是重复的,还不是 Forked 而来。
  16. matlab emd imf波形,emd分解后画出IMF的波形
  17. 二级路由器设置,二级路由器无法上网
  18. 计算机网络之应用层Tips
  19. 至多包含 K 个不同字符的最长子串
  20. 摩摩哒蓄势再起:最新自主研发产品摩舒椅上线小米有品众筹平台

热门文章

  1. adb echo shell 覆盖_一次写shell脚本的经历记录
  2. html5media 网页播放视频,html5media 在IE8播放视频黑屏
  3. Springboot/Cloud集成Sentinel 和 入门实战
  4. java 批量为图片添加图标水印和文字水印
  5. java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä'
  6. Mysql 5.7 错误号码1862 Your password has expired. To log in you must change it using a client...
  7. Vue 过渡效果的组件
  8. cstring 不明确_股价不可预测明确时间点的涨跌
  9. 计算机机房建设目标是什么,计算机机房建设方案计划.doc
  10. qt解决循环创建的控件,每个都绑定相同的槽函数时出现的一对多响应问题