哈夫曼编码译码器
哈夫曼编码译码器
软件综合课程设计哈夫曼编码/译码器二叉排序树的实现二〇一四年六月二叉排序树的实现一、内容用顺序和二叉链表作存储结构1)以回车('\n')为输入结束标志,输入数列L,生成一棵二叉排序树T;2)对二叉排序树T作中序遍历,输出结果;3)输入元素x,查找二叉排序树T,若存在含x的结点,则删除该结点,并作中序遍历(执行操作2);否则输出信息“无x”;二、程序代码#include <stdio.h>#include <stdlib.h>#define MAX 64 //规定树中结点的最大数目typedefstruct node{ //定义数据结构intltag,rtag; //表示child域指示该结点是否孩子char data; //记录结点的数据struct node *lchild; //记录左右孩子的指针struct node *rchild;}TBtree;TBtree *Que[MAX]; //建队,保存已输入的结点的地址TBtree *CreatTree(){ //建树函数,返回根指针charch;intfront,rear;TBtree *T,*s;T=NULL;front=1;rear=0; //置空二叉树printf("进行初始化,创建二叉树(按满二叉树序号顺序输入,中间的虚节点用\"@\"表示,\"#\"结束)\n");ch=getchar(); //输入第一个字符while(ch!='#') //判断是否为结束字符{s=NULL;if(ch!='@') //判断是否为虚结点{s=(TBtree *)malloc(sizeof(TBtree));s->data=ch;s->lchild=NULL;s->rchild=NULL;s->rtag=0;s->ltag=0;}rear++;Que[rear]=s; //将结点地址加入队列中if(rear==1)T=s; //输入为第一个结点为根结点else{if(s!=NULL&&Que[front]!=NULL) //孩子和双亲结点均不是虚结点{if(rear%2==0)Que[front]->lchild=s;elseQue[front]->rchild=s;}if(rear%2==1)front++;}ch=getchar();}return T;}void Inorder(TBtree *T) //中序遍历{if(T!=NULL){if(T->ltag!=1)Inorder(T->lchild);printf("%c→",T->data);if(T->rtag!=1)Inorder(T->rchild);}}TBtree *pre=NULL;void PreThread(TBtree *root) //中序线索化算法,函数实现{TBtree *p;p=root;if(p){PreThread(p->lchild);//线索化左子树if(pre&&pre->rtag==1)pre->rchild=p; //前驱结点后继线索化if(p->lchild==NULL){p->ltag=1;p->lchild=pre;}if(p->rchild==NULL) //后继结点前驱线索化p->rtag=1;pre=p;PreThread(p->rchild);}}void PrintIndex(TBtree *t) //输出线索{TBtree *f;f=t;if(f){if(f->ltag==1&&f->lchild==NULL&&f->rtag==1)printf("【%c】",f->data); //如果是第一个结点if(f->ltag==1&&f->lchild!=NULL)printf("%c→【%c】",f->lchild->data,f->data); //如果此结点有前驱就输出前驱和此结点if(f->ltag==1&&f->rtag==1&&f->rchild!=NULL)printf("→%c",f->rchild->data); //如果此结点有前驱也有后继,就输出后继else if(f->rtag==1&&f->rchild!=NULL)printf("【%c】→%c",f->data,f->rchild->data);//如果没有前驱,就输出此结点和后继printf("\n");if(f->ltag!=1)PrintIndex(f->lchild);if(f->rtag!=1)PrintIndex(f->rchild);}}TBtree *SearchChild(TBtree *point,charfindnode) //查找孩子结点函数{TBtree *point1,*point2;if(point!=NULL){if(point->data==findnode) return point;elseif(point->ltag!=1){point1=SearchChild(point->lchild,findnode);if(point1!=NULL)return point1;}if(point->rtag!=1){point2=SearchChild(point->rchild,findnode);if(point2!=NULL)return point2;}return NULL;}return NULL;}TBtree *SearchPre(TBtree *point,TBtree *child) //查找父亲结点函数{TBtree *point1,*point2;if(point!=NULL){if((point->ltag!=1&&point->lchild==child)||(point->rtag!=1&&point->rc hild==child)) return point;elseif(point->ltag!=1){point1=SearchPre(point->lchild,child);if(point1!=NULL)return point1;}if(point->rtag!=1){point2=SearchPre(point->rchild,child);if(point2!=NULL)return point2;}return NULL;}elsereturn NULL;}void Insert(TBtree *root){charch;char c;TBtree *p1,*child;printf("请输入要插入的结点的信息:");scanf("%c",&c);scanf("%c",&c);p1=(TBtree *)malloc(sizeof(TBtree)); //插入的结点信息p1->data=c;p1->lchild=NULL;p1->rchild=NULL;p1->rtag=0;p1->ltag=0;printf("输入查找的结点信息:");scanf("%c",&ch);scanf("%c",&ch);child=SearchChild(root,ch); //查孩子结点的地址if(child==NULL){printf("没有找到结点\n");return ;}else printf("发现结点%c\n",child->data);if(child->ltag==0) //当孩子结点有左孩子的时候{//p2=child;child=child->lchild;while(child->rchild&&child->rtag==0) //找到左子树下,最右结点child=child->rchild;printf("发现结点%c\n",child->data);p1->rchild=child->rchild; //后继化p1->rtag=1;child->rtag=0;child->rchild=p1; //连接p1->lchild=child; //前驱化p1->ltag=1;}else //当孩子结点没有左孩子的时候{p1->lchild=child->lchild; //前驱化child->ltag=0;p1->ltag=1;child->lchild=p1;p1->rchild=child;p1->rtag=1;}printf("\n插入结点操作已经完成,并同时完成了线索化的恢复\n");}voidDeleteNode(TBtree *t){TBtree *child,*pre,*s,*q;charch;printf("输入查找的结点信息:");ch=getchar();ch=getchar();child=SearchChild(t,ch);printf("发现结点:%c\n",child->data);printf("ltag=%d,rtag=%d\n",child->ltag,child->rtag);pre=SearchPre(t,child);printf("发现结点:%c\n",pre->data);if(NULL==child){printf("没有找到结点:");return;}system("pause");if(child==pre->lchild||child==pre) //是父亲结点的左孩子{if(1==child->ltag&&1==child->rtag)//孩子结点无左右{pre->lchild=child->lchild;pre->ltag=1;if(child->lchild!=NULL)if(child->lchild->rtag==1)child->lchild->rchild=pre;free(child);}else if(1!=child->ltag&&1==child->rtag)//孩子结点有左无右{pre->lchild=child->lchild;s=child->lchild;while(s->rchild&&s->rtag!=1)s=s->rchild;s->rchild=child->rchild;free(child);}else if(1==child->ltag&&1!=child->rtag)//孩子结点有右无左{pre->lchild=child->rchild;s=child->rchild;while(s->lchild&&s->ltag!=1) //查找左子树最左下点s=s->lchild;s->lchild=child->lchild;if(child->lchild!=NULL)if(child->lchild->rtag==1)child->lchild->rchild=pre;free(child);}else if(1!=child->ltag&&1!=child->rtag)//孩子结点左右都有 {pre->lchild=child->lchild;s=child->rchild;while(s->lchild&&s->ltag!=1)//右子树的左下s=s->lchild;q=child->lchild;while(q->rchild&&q->rtag!=1)//左子树的右下q=q->rchild;q->rchild=child->rchild;q->rtag=0;s->lchild=q;free(child);}}if(child==pre->rchild) //是父亲结点的右孩子{if(1==child->ltag&&1==child->rtag)//孩子结点无左右{pre->rchild=child->rchild;pre->rtag=1;if(child->rchild!=NULL)if(child->rchild->ltag==1)child->rchild->lchild=pre;free(child);}else if(1!=child->ltag&&1==child->rtag)//孩子结点有左无右{pre->rchild=child->lchild;s=child->lchild;while(s->rchild&&s->rtag!=1)s=s->rchild;s->rchild=child->rchild;if(child->rchild!=NULL)if(child->rchild->ltag==1)child->rchild->lchild=pre;free(child);}else if(1==child->ltag&&1!=child->rtag)//孩子结点有右无左{pre->rchild=child->rchild;s=child->rchild;while(s->lchild&&s->ltag!=1)s=s->lchild;s->lchild=child->lchild;free(child);}else if(1!=child->ltag&&1!=child->rtag)//孩子结点左右都有{pre->rchild=child->rchild;s=child->rchild;while(s->lchild&&s->ltag!=1)//右子树的左下s=s->lchild;q=child->lchild;while(q->rchild&&q->rtag!=1)//左子树的右下q=q->rchild;s->lchild=child->lchild;s->ltag=0;q->rchild=s;free(child);}}printf("\n删除结点操作已经完成,并同时完成了线索化的恢复\n");printf("find %c",child->data);return;}int main(void){TBtree *T;inti;T=CreatTree();printf("\n");i=1;while(i){printf("\t1.二叉树的线索化\n");printf("\t2.线索二叉树插入操作\n");printf("\t3.线索二叉树删除操作\n");printf("\t4.中序输出\n");printf("\t5.线索输出\n");printf("\t0.退出\n");printf("\t 请选择:");scanf("%d",&i);printf("\n");switch(i){case 1:PreThread(T);printf("\t已经实现二叉树的线索化\n");printf("\n");break;case 2:Insert(T);printf("\n");break;case 3:DeleteNode(T);printf("\n");break;case 4:Inorder(T);printf("\n");break;case 5:PrintIndex(T);break;case 0:exit(1);default:printf("error\n\t请继续选择:");}}return 0;}三.运行结果二叉树创建:二叉树线索化:线索二叉树插入结点:线索二叉树删除结点:四、设计总结通过这次设计,我懂得了学习的重要性,了解到理论知识与实践相结合的重要意义,学会了坚持、耐心和努力,这将为自己今后的学习和工作做出了最好的榜样。
哈夫曼编码译码器
目录一、系统开发的背景 (1)二、系统分析与设计 (1)(一)系统功能要求 (1)(二)系统模块结构设计 (2)三、系统的设计与实现 (2)(一)哈夫曼树的定义 (2)四、系统测试 (3)(一)测试MAIN_FORM()函数 (3)(二)测试VOID HFMCODING(HFMTREE &HT,HFMCODE &HC,INT N)函数,测试的结果 (4)(三)测试编码函数,测试结果如下 (4)(四)测试译码函数,测试结果如下 (4)(五)测试退出函数,测试结果如下 (5)五、总结(实验心得) (5)六、附件(源代码) (6)哈夫曼编译码一、系统开发的背景随着计算机的应用越来越普遍,它的应用早已不局限于简单的数值运算,而涉及到问题的分析、数据结构框架的设计以及设计最短路线等复杂的非数值处理和操作。
为了确保能够更好的保存机密性文件、安全的传送某一个重要的东西,利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。
对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码器。
因此我为这样的信息收发站设计了一个简单的哈夫曼的编码/译码器。
二、系统分析与设计(一)系统功能要求一个完整的哈夫曼编码/译码器应具有以下功能:1、初始化:从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。
2、编码:利用以建好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
3、译码:利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。
4、退出。
(二)系统模块结构设计通过对此功能的分析,哈夫曼编码/译码器的功能如图1所示。
哈夫曼编码/译码器1.初始化2.编码3.译码0.退出图1 哈夫曼编码/译码器的功能图通过上图的功能分析,把整个系统划分为4个模块:1、初始化,该模块主要实现:哈夫曼二叉树的定义以及哈夫曼二叉树的建立,借助函数void hfmcoding()来实现;2、编码,该模块主要实现:把输入的字符和代码以二进制的形式存储起来,借助函数void hfmcoding()来实现;3、译码,该模块主要实现:把以二进制形式存储起来的代码,转换成字符的形式并输出,借助函数来实现;4、退出。
哈夫曼编码译码器课程设计
哈夫曼编码译码器课程设计1.哈夫曼编码是一种有效的数据压缩算法,通过将最常用的字符编码为较短的比特串,最大限度地减少了存储空间。
本文档介绍一个哈夫曼编码译码器的设计和实现,该译码器可以实现从原始文本到哈夫曼编码的转换,并且可以从哈夫曼编码还原出原始文本。
2. 设计和实现本译码器的开发采用Python语言,主要分为两部分:哈夫曼编码和译码两部分。
2.1 哈夫曼编码哈夫曼编码的过程主要分为两步:1.统计每个字符出现的频率,并生成一个频率表。
2.根据频率表生成哈夫曼树,并生成相应的编码表。
以下是用于生成哈夫曼编码的Python代码:import heapqfrom collections import defaultdictclass Node:def__init__(self, freq, char=None, left=None, right=None): self.freq = freqself.char = charself.left = leftself.right = rightdef__lt__(self, other):return self.freq < other.freqdef__eq__(self, other):return self.freq == other.freqdef build_tree(data):freq = defaultdict(int)for char in data:freq[char] +=1q = [Node(freq[char], char) for char in freq]heapq.heapify(q)while len(q) >1:left = heapq.heappop(q)right = heapq.heappop(q)parent = Node(left.freq + right.freq, left.char + right.char, l eft, right)heapq.heappush(q, parent)return q[0]def generate_codes(node, current_code='', codes={}):if node is None:returnif node.char is not None:codes[node.char] = current_codegenerate_codes(node.left, current_code +'0', codes)generate_codes(node.right, current_code +'1', codes)return codes通过调用build_tree()函数来生成哈夫曼树,并调用generate_codes()函数来生成编码表。
数据结构课程设计哈夫曼编码译码器
哈夫曼编码译码器哈夫曼编码译码器a)需求分析:一个完整的系统应具有以下功能:(l)I:初始化。
从终端读入字符集大小n,及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmtree中。
(2)C:编码。
利用已建好的哈夫曼树(如不在内存,则从文件hfmtree 中读入),对文件tobetrans中的正文进行编码,然后将结果存入文件codefile中。
(3)D:编码。
利用已建好的哈夫曼树将文件codefile中的代码进行译码,结果存入文件textfile中。
(4)P:印代码文件。
将文件codefile以紧凑格式显示在终端上,每行50个代码。
同时将此字符形式的编码文件写入文件codeprint中。
(5)T:印哈夫曼树。
将已在内存中的哈夫曼树以直观的方式 (树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件treeprint 中可以根据题目要求把程序划成5个模块,设计成菜单方式,每次执行一个模块后返回菜单。
除了初始化(I)过程外,在每次执行时都经过一次读取磁盘文件数据。
这是为了如果在程序执行后一直没有进行初始化(I)过程,为了能使后面的操作顺利进行,可以通过读取旧的数据来进行工作。
比如:如果程序的工作需要的字符集和权值数据是固定的,只要在安装程序时进行一次初始(I)化操作就可以了。
在再次运行程序时,不管进行那项操作都可以把需要的数据读入到内存。
b)概要设计本程序主要用到了三个算法。
(1)哈夫曼编码在初始化(I)的过程中间,要用输入的字符和权值建立哈夫曼树并求得哈夫曼编码。
先将输入的字符和权值存放到一个结构体数组中,建立哈夫曼树,将计算所得的哈夫曼编码存储到另一个结构体数组中。
(2)串的匹配在编码(D)的过程中间,要对已经编码过的代码译码,可利用循环,将代码中的与哈夫曼编码的长度相同的串与这个哈夫曼编码比较,如果相等就回显并存入文件。
(3)二叉树的遍历在印哈夫曼树(T)的中,因为哈夫曼树也是二叉树,所以就要利用二叉树的先序遍历将哈夫曼树输出c)详细设计构造树的方法如下:初始化:每个字符就是一个结点,字符的频度就是结点的权;1、将结点按频度从小到大排序;2、选取频度最小的两个结点,以它们为儿子,构造出一个新的结点;新结点的权值就是它两个儿子的权值之和;构造之后,从原来的结点序列里删除刚才选出的那两个结点,但同时将新生成的结点加进去;3、如果结点序列里只剩下一个结点,表示构造完毕,退出。
哈夫曼编码译码器数据结构C语言
哈夫曼编码译码器数据结构C语言哈夫曼编码译码器数据结构C语言⒈简介本文档旨在介绍一个使用C语言实现的哈夫曼编码译码器的数据结构。
哈夫曼编码是一种用于数据压缩的算法,它通过将频率较高的字符用较短的编码表示,从而实现数据的压缩和解压缩。
⒉哈夫曼编码(Huffman Coding)基本概念⑴字符频率统计在进行哈夫曼编码之前,我们首先需要统计每个字符在待编码的数据中出现的频率。
通过遍历数据,记录每个字符的出现次数,我们可以得到一个字符频率的统计表。
⑵构建哈夫曼树通过字符频率的统计表,我们可以构建一个哈夫曼树。
哈夫曼树是一种二叉树,其中每个叶节点表示一个字符,而每个内部节点表示一个权重,即两个子节点的频率之和。
⑶哈夫曼编码在哈夫曼树构建完成后,我们可以根据树的结构每个字符的编码。
哈夫曼编码的特点是没有任何一个字符的编码是另一个字符编码的前缀,这种编码方式称为前缀编码。
⑷哈夫曼译码根据字符的哈夫曼编码,我们可以将编码后的数据进行解码,还原为原始的数据。
通过遍历哈夫曼树,从根节点开始,根据每个二进制位的取值进行向左或向右的移动,直至叶节点,然后获取该叶节点对应的字符。
⒊数据结构设计⑴结点结构定义一个哈夫曼树的结点结构,包含以下字段:●`char data`:字符●`int frequency`:字符的频率●`int is_leaf`:是否为叶节点●`struct Node left_child`:左子节点●`struct Node right_child`:右子节点⑵频率统计表使用一个数组或链表来记录每个字符的频率统计信息,包含以下字段:●`char data`:字符●`int frequency`:字符的频率⑶编码表使用一个数组或链表来记录每个字符的哈夫曼编码,包含以下字段:●`char data`:字符●`char code`:编码⒋算法流程⑴字符频率统计算法步骤:⒈初始化频率统计表为空。
⒉读取待编码的数据。
哈夫曼码编、译码器的实现
根据下面给出的存储结构定义 typedef struct // 定义哈夫曼树中每个结点结构体类型 { char ch; //结点字符信息 int weight; // 定义一个整型权值变量 int lchild; // 定义左、右孩子及双亲指针 int rchild; int parent; } HTNode; typedef HTNode HFMT[MAXLEN]; //用户自定义HFMT数组类型 typedef char** HfCode;//动态分配字符数组存储哈夫曼编码表 (7)基本操作的函数设计 void InitHFMT(HFMT T);//初始化哈夫曼树 void InputWeight(HFMT T,char* weightFile);// 输入权值 void SelectMin(HFMT T,int i,int *p1,int *p2); //选择所有结点中较小的结点 void CreatHFMT(HFMT T);// 构造哈夫曼树,T[2*n-1]为其根结点 void PrintHFMT (HFMT T);// 输出向量状态表 void printHfCode(HfCode hc);//输出字符的哈夫曼编码序列 HfCode hfEnCoding(HFMT T);//利用构成的哈夫曼树生成字符的编码 void print_HuffmanTree(HFMT HT,int t,int i)//按树形形态输出哈 夫曼树的形态 void Encoder(char* original,char* codeFile,HfCode hc,HFMT HT); //利用已建好的哈夫曼树,对original文件中要传输的原始数据进行编 码, //将编码结果存入文件codeFile中 void Decoder(char* codeFile ,char* textFile,HFMT HT); //利用已建好的哈夫曼树,对传输到达的codeFile中的数据代码进行译
哈夫曼编、译码器
《数据结构--C++实现》课程设计报告学院:计算机学院专业班级:软件项目题目:哈夫曼编/译码器【问题描述】利用哈夫曼编码可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对传输数据预先编码,在接收端将传来的数据进行译码。
对于双工信道,每端都需要一个完整的编/译码器。
试为这样的通信端编写一个哈夫曼编/译码器。
一.需求分析1.运行环境(软、硬件环境>Visual studio 20082.程序实现的功能初始化:输入一串字符<正文),计算不同字符<包括空格)的数目以及每种字符出现的频率<以该种字符出现的次数作为其出现频率),根据权值建立哈夫曼树,输出每一种字符的哈夫曼编码。
编码:利用求出的哈夫曼编码,对该正文<字符串)进行编码,并输出。
译码:对于得到的一串编码,利用已求得的哈夫曼编码进行译码,将译出的正文输出。
输出哈夫曼树形态:以树的形式输出哈夫曼树。
3.程序的输入一串字符(英文>或短文(英文>4.程序的输出根据用户需求不同有相应的输出5.测试数据there are three students二.设计说明1.算法设计的思想建立链表类、栈类、队列类、哈夫曼结点类、哈夫曼树类,通过主函数调用的方法来实现程序的功能。
2.主要的数据结构说明链表模板类:template<class Type>//模板链表类class LinkList{private :HuaffmanTreeNode<Type> *head。
//链表的头结点public:Type List[1000]。
LinkList(void>。
~LinkList(void>。
HuaffmanTreeNode<Type> *GetHead(>。
//void SetHead(HuaffmanTreeNode<Type> *h>。
实验九 哈夫曼编码-译码器
实验九哈夫曼编码-译码器实验十哈夫曼编/译码器一、实验目的(1)掌握哈夫曼树的构造和应用(2)利用哈夫曼方法及其编/译码技术实现对传输信息编码/译码系统二、实验内容[问题描述](设计性实验)哈夫曼树很易求出给定字符集及其概率(或频度)分布的最优前缀码。
哈夫曼编码正是一种应用广泛且非常有效的数据压缩技术。
该技术一般可将数据文件压缩掉20,至90,,其压缩效率取决于被压缩文件的特征。
利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传送电文须预先编码,在接收须将传送来的数据进行译码。
请自行设计实现一个具有初始化、编码、译码、输入/输出等功能的哈夫曼码的编码/译码系统。
并实现以下报文的编码和译码:“this program is my favorite”。
[测试数据]某通信的电文字符集为26个英文字母及空格字符,其出现频度如下表所示:[实现提示]如何创建哈夫曼树及如何求得各结点对应的哈夫曼编码算法:参见ppt。
1、设计思想描述(1) 问题分析。
(2) 哈夫曼树中各结点的结构描述(提示:图示)。
(3) 哈夫曼树的存储结构描述(提示:分析采用顺序存储还是利用链式存储等)。
2、主要算法设计与实现[要求]1)、利用类模板来实现。
2)、类中各成员函数要求给出自行设计的算法步骤描述及主要设计思想。
3)、给出类中各成员函数算法设计实现。
4)、对自行设计的各算法进行评估(提示:时间复杂度、空间复杂度等)。
#include<iostream>#include<string>using namespace std;const int MAX = 1000;class HTree;class HTNode{friend class HTree;unsigned int weight;unsigned int parent, lchild, rchild; };class HuCode{friend class HTree;char *ch; //字符的编码char data;//被编码的字符};//动态分配数组存储哈夫曼编码表。
数据库实验哈夫曼编译码器
汇报人:XX
目录
添加目录标题
01
哈夫曼编译码器原理
02
数据库实验哈夫曼编译码 器实现
03
数据库实验哈夫曼编译码 器应用场景
04
数据库实验哈夫曼编译码 器与其他编译码器的比较
05
数据库实验哈夫曼编译码 器的发展趋势和未来展望
06
添加章节标题
哈夫曼编译码器 原理
哈夫曼编码原理
感谢您的观看
汇报人:XX
与算术编译码的比较
编码方式:哈夫曼编码采用可变长 度编码,而算术编码采用固定长度 编码
编码效率:哈夫曼编码通常比算术 编码更高效,因为它可以更好地利 用数据分布信息
精度:算术编码具有更高的精度, 因为它可以将概率估计精确到小数 点后多位
适用场景:哈夫曼编码适用于数据 量较小且概率分布不均的情况,而 算术编码适用于数据量较大且概率 分布均匀的情况
哈夫曼编码算法的改进方向
优化编码效率:提高哈夫曼编码的压缩比和编码速度 动态调整编码表:根据数据特征自适应调整哈夫曼编码表 降低误码率:改进哈夫曼编码的解码算法,降低解码错误率 跨平台兼容性:提高哈夫曼编码在不同平台和环境下的兼容性和稳定性
哈夫曼编码与其他技术的结合应用
哈夫曼编码与 压缩技术结合: 提高数据压缩
效率
哈夫曼编码与 加密技术结合: 增强数据传输
安全性
哈夫曼编码与 云计算技术结 合:实现大规
模数据处理
哈夫曼编码与 人工智能技术 结合:优化算 法提高编码效
率
哈夫曼编码在物联网和云计算领域的应用前景
物联网中的数据传输:哈夫曼编码能够有效地压缩数据,降低传输成本和提高传输效率,尤其在物联网领 域中,对于大量数据的处理和传输具有重要意义。
(完整word版)哈夫曼编码译码器数据结构C语言
一、需求分析目前,进行快速远距离通信的主要手段是电报,即将需传送的文字转化成由二级制的字符组成的字符串。
例如,假设需传送的电文为“ABACCDA”,它只有4种字符,只需两个字符的串,便可以分辨。
假设A、B、C、D、的编码分别为00,01,10和11,则上述7个字符的电文便为“00010010101100”,总长14位,对方接受时,可按二位一分进行译码。
当然,在传送电文时,希望总长尽可能地短。
如果对每个字符设计长度不等的编码,且让电文中出现次数较多的字符采用尽可能短的编码,则传送电文的总长便可减少。
如果设计A、B、C、D的编码分别为0,00,1,01,则上述7个字符的电文可转换成总长为9的字符串“000011010”。
但是,这样的电文无法翻译,例如传送过去的字符串中前4个字符的字串“0000”就可以有很多种译法,或是“AAAA”或者“BB”,或者“ABA”等。
因此,若要设计长短不等的编码,则必须是任一字符的编码都不是另一个字符的编码的前缀,这种编码称作前缀编码。
然而,如何进行前缀编码就是利用哈夫曼树来做,也就有了现在的哈夫曼编码和译码。
二、概要设计利用哈夫曼树编/译码(一)、建立哈夫曼树(二)、对哈夫曼树进行编码(三)、输出对应字符的编码(四)、译码过程主要代码实现:struct code //结构体的定义{char a;int w; int parent; int lchild; int rchild;};void creation(code *p,int n,int m); //建立哈夫曼树 void coding(code *p,int n);//编码void display(code *p,int n,int m);//输出函数void translate(char **hc,code *p,int n);//译码三、 详细设计(一)、建立哈夫曼树(二)、对哈夫曼树进行编码主要代码实现:for(c=i,f=p[i].parent;f!=0;c=f,f=p[f].parent) { if(p[f].lchild==c)//左孩子编码为'0'{ cd[--start]='0';}1 2 3 4 5 * * * 6 7序号: 权值: 1 23 4 3 6 10 106 图3-1 图从叶子到根逆向求编码else //右孩子编码为'1'{ cd[--start]='1';}}(三)、输出对应字符的码(四)、译码过程主要代码实现:if(strcmp(a,hc[i])==0) //比较两个字符串是否相等,相等则输出0 { for(c=2*n-1,j=0;a[j]!='\0';j++) //从根出发,按字符'0'或'1'确定找左孩子或右孩子 {if(a[j]=='0') //左孩子{ c=p[c].lchild;}else图3-4表3-1从跟到叶子顺向求字符{ c=p[c].rchild; //右孩子}}四、 调试分析(一)、数字的输入判断(二)、字母的输入判断(三)、程序是否继续进行的判断五、 用户手册(一)、首先根据提示输入初始化数据,提示输入一个数字,请输入一个数a ,0<a<9999;提示输入一个1图3-5图4-1图4-2图4-3字母,则请输入一个字母(a~z)或者(A~Z)中的一个字符;请勿在输入一个数字后再输入一个字符,或者在输入一个字符后再输入一个数字。
哈夫曼编码译码器实验报告
哈夫曼编码译码器实验报告实验名称:哈夫曼编码译码器实验一、实验目的:1.了解哈夫曼编码的原理和应用。
2.实现一个哈夫曼编码的编码和译码器。
3.掌握哈夫曼编码的编码和译码过程。
二、实验原理:哈夫曼编码是一种常用的可变长度编码,用于将字符映射到二进制编码。
根据字符出现的频率,建立一个哈夫曼树,出现频率高的字符编码短,出现频率低的字符编码长。
编码过程中,根据已建立的哈夫曼树,将字符替换为对应的二进制编码。
译码过程中,根据已建立的哈夫曼树,将二进制编码替换为对应的字符。
三、实验步骤:1.构建一个哈夫曼树,根据字符出现的频率排序。
频率高的字符在左子树,频率低的字符在右子树。
2.根据建立的哈夫曼树,生成字符对应的编码表,包括字符和对应的二进制编码。
3.输入一个字符串,根据编码表将字符串编码为二进制序列。
4.输入一个二进制序列,根据编码表将二进制序列译码为字符串。
5.比较编码前后字符串的内容,确保译码正确性。
四、实验结果:1.构建哈夫曼树:-字符出现频率:A(2),B(5),C(1),D(3),E(1) -构建的哈夫曼树如下:12/\/\69/\/\3345/\/\/\/\ABCDE2.生成编码表:-A:00-B:01-C:100-D:101-E:1103.编码过程:4.译码过程:5.比较编码前后字符串的内容,结果正确。
五、实验总结:通过本次实验,我了解了哈夫曼编码的原理和应用,并且实现了一个简单的哈夫曼编码的编码和译码器。
在实验过程中,我充分运用了数据结构中的树的知识,构建了一个哈夫曼树,并生成了编码表。
通过编码和译码过程,我进一步巩固了对树的遍历和节点查找的理解。
实验结果表明,本次哈夫曼编码的编码和译码过程正确无误。
在实验的过程中,我发现哈夫曼编码对于频率较高的字符具有较短的编码,从而实现了对字符串的高效压缩。
同时,哈夫曼编码还可以应用于数据传输和存储中,提高数据的传输效率和存储空间的利用率。
通过本次实验,我不仅掌握了哈夫曼编码的编码和译码过程,还深入了解了其实现原理和应用场景,加深了对数据结构和算法的理解和应用能力。
哈夫曼编码译码器
哈夫曼编码译码器#include<stdio.h> #include<conio.h> #include<malloc.h> #include<string.h> #include<stdlib.h>#define ERROR 0; #define OK 1;typedef int Status;typedef struct{ unsigned int weight; int key;int parent,lchild,rchild;}HTNode,*HuffmanTree;typedef char * * HuffmanCode;int **KEY;int N;Status GetData(){ FILE *fp;int key[100][2]; int ch,k,i,tem; char str[16];fp=fopen("data.txt","r");k=0;while(!feof(fp)){ch=fgetc(fp);i=0;while(ch!=' '){ str[i]=ch;i++;ch=fgetc(fp);}str[i]='\0';//printf("%d\n",strcmp(str," 空格"));if(!strcmp(str," 空格")){key[k][0]=' ';}else{ key[k][0]=str[0];}ch=fgetc(fp);tem=0;while(ch!='\n'&&ch!=EOF){ tem=tem*10+ch-'0'; ch=fgetc(fp); } key[k][1]=tem; //printf("%c,%d\n",key[k][0],key[k][1]);k++;}KEY=(int * *)malloc(k*sizeof(int *));if(!KEY){return ERROR;}for(i=0;i<k;i++){KEY[i]=(int*)malloc(2*sizeof(int));if(!KEY[i]){return ERROR;KEY[i][0]=key[i][0]; KEY[i][1]=key[i][1]; }N=k; fclose(fp); return OK;}Status InitHuffmanTree(HuffmanTree &HT){int i;HT=(HTNode *)malloc((2*N-1)*sizeof(HTNode)); if(!HT){ return ERROR;} for(i=0;i<N;i++){HT[i].weight=KEY[i][1]; HT[i].key=KEY[i][0]; HT[i].parent=-1; HT[i].lchild=-1;HT[i].rchild=-1;} for(;i<2*N-1;i++){HT[i].parent=-1;} return OK;}void Select(HuffmanTree &HT,int n,int &fi,int &si){ int i=0,tem; if(n>=2){while(((HT+i)->parent)!=-1){ i++;}fi=i;i++;while((HT+i)->parent!=-1){ i++;}si=i;if((HT+fi)->weight>(HT+si)->weight){ tem=fi;fi=si;si=tem;}for(i++;i<n;i++){if((HT+i)->parent==-1){ if((HT+i)->weight<(HT+fi)->weight){ si=fi; fi=i;}else{if((HT+i)->weight<(HT+si)->weight){ si=i;}}}int HuffmanTreeAllReady(HuffmanTree HT,int m){int sum=0,i;for(i=0;i<m;i++){ if((HT+i)->parent==-1){ sum++;}if(sum>1){return 0;}}return 1;}void CreateHuffmanTree(HuffmanTree &HT,int n){int s1,s2;while(!HuffmanTreeAllReady(HT,n)){ Select(HT,n,s1,s2);HT[n].parent=-1;HT[n].lchild=s1;HT[n].rchild=s2;HT[n].weight=HT[s1].weight+HT[s2].weight; HT[s1].parent=n; HT[s2].parent=n;n++;}void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int n){ char * str;int len=0,tem,i,j;unsigned int p;str=(char *)malloc(n*sizeof(char));for(i=0;i<n;i++){p=i;len=0;while((tem=HT[p].parent)!=-1){ if(HT[tem].lchild==p){ str[len]='0'; }else{str[len]='1';}len++;p=tem;}HC[i]=(char *)malloc((len+1)*sizeof(char));if(HC[i]){for(j=0;j<len;j++){HC[i][j]=str[len-1-j];H c ==_e n lr /ss s e n H /s—p 「Hf(=%a%2n=HC==0L_en)JvoidoufpufHuffmancodeIuffmancodeHe)宀5'二f o 「T o x N T +)宀 p 「imf(=%c.VvoidcodingTuffmancodeHe)宀F_LE-4P Winf ch J八f p H f o p e n v &a s H .x f ==3八 fqHfopenv&®®H .b d ==w +=)八 chHfgeo(fp)八wh=e(ch一 HEOF)宀i f o h H H :)宀110 八e-se 宀ll c h 」A 匚一八1p 「Hf(=%c=chxuprimf(=%s=HCs- c h -l g e o (f p )-fcose(fp)八fcose(fq)八prinmoK云)voidDecoding(HuffmanTreeHTjnfN)宀F_LE-4P Winfch J八fqHfopenv ^a s H .x f ==w +=)八 fpHfopenv孺chHfgeo(fp)八wh=e(ch 一 HEOF)宀ll 2*N 2w h =e (H T s _c h i _d H ±QO QO H T s 「c h i _d H ±)宀i f o h H H O )宀ll H T s o h 云e-se 宀llH T s 「c h i _a—prinff(=%c=ch)八 chHfgeo(fp)八//printf("%c",ch); fputc(HT[t].key,fq); //printf("%c",HT[t].key);//printf("%s",HC[t]); //ch=fgetc(fp);}fclose(fp);fclose(fq);printf("OK\n");}int main(){HuffmanTree HT;HuffmanCode HC;int n,i,j,a,b,x;GetData();HC=(char * *)malloc((N)*sizeof(char *));InitHuffmanTree(HT);CreateHuffmanTree(HT,N);HuffmanCoding(HT,HC,N); //for(i=0;i<2*N-1;i++){ //printf("%d,%d,%d,%c,%d,%d\n",i,HT[i].parent,HT[i].weight,HT[i].key,H T[i].lchild,HT[i].rchild);//}printf(" 选项:1. 输出哈夫曼编码2. 输入明文得到密文3. 输入密文得到明文0. 退出\n");printf(" 输入选项:");while(scanf("%d",&x),x){ switch(x){case 1 :{OutputHuffmanCode(HC); break;}case 2 :{Coding(HC);}case 3 :{Decoding(HT,N);}}printf(" 输入: 1. 输出哈夫曼编码2. 输入明文得到密文3. 输入密文得到明文0.退出\n");printf(" 输入选项:");}return 0;。
数据结构哈夫曼编译码器
数据结构课设哈夫曼编译码器学号:姓名:提交日期:成绩:一、实验名称哈夫曼编/译码器的实现二、实验要求【问题描述】利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传来数据预先编码,在接收端将传来的数据进行译码(复原)。
对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。
试为这样的信息收发站写一个哈夫曼码的编/译码系统。
【基本要求】一个完整的系统应具有以下功能:(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中。
【测试数据】(1)利用教科书例 6-2 中的数据调试程序。
(2)用下表给出的字符集和频度的实际统计数据建立哈夫曼树 , 并实现以下报文的编码和译码:"THIS PROGRAM IS MY FAVORITE"。
三、 需求分析Huffman 编码是一种可变长编码方式,是由美国数学家David Huffman 创立的,是二叉树的一种特殊转化形式。
编码的原理是:将使用次数多的代码转换成长度较短的代码,而使用次数少的可以使用较长的编码,并且保持编码的唯一可解性。
哈夫曼编码译码器数据结构C语言
哈夫曼编码译码器数据结构C语言哈夫曼编码译码器数据结构C语言文档1.引言本文档介绍了一个基于哈夫曼编码的译码器的设计和实现。
哈夫曼编码是一种无损压缩算法,通过对出现频率较高的符号进行较短的编码,来减小数据的存储或传输所需的空间。
2.哈夫曼编码原理在哈夫曼编码中,使用一颗二叉树,将出现频率较高的符号表示为树的较浅的节点,而出现频率较低的符号表示为树的较深的节点。
通过遍历整个二叉树,可以得到每个符号对应的哈夫曼编码。
2.1 创建哈夫曼树首先,根据每个符号的出现频率,创建一颗包含所有符号的节点的最小堆。
然后,根据最小堆的特性,每次从最小堆中选取两个出现频率最低的节点,并合并为一个新节点。
重复这个过程,直到最小堆中只剩下一个节点,即哈夫曼树的根节点。
2.2 哈夫曼编码通过遍历哈夫曼树,可以得到每个符号对应的哈夫曼编码。
在遍历的过程中,左孩子表示编码中的“0”,右孩子表示编码中的“1”。
每次左移一个位,表示向左遍历,每次右移一个位,表示向右遍历。
3.数据结构设计下面介绍了本文档中所使用的各种数据结构和相关函数的设计。
3.1 结构定义```cstruct Node {char symbol。
int frequency。
struct Node leftChild。
struct Node rightChild。
}。
```3.2 方法定义```c// 创建哈夫曼树struct Node createHuffmanTree(char symbols, int frequencies, int size)// 哈夫曼编码表void generateHuffmanTable(struct Node root, char huffmanTable, char currentCode)// 哈夫曼编码char encode(char data, char huffmanTable)// 哈夫曼译码char decode(char encodedData, struct Node root)```4.实现细节在这个章节中,我们将会具体讨论各个方法的实现细节和使用示例。
哈夫曼编码译码器系统
哈夫曼编码译码器系统目录(1)一、系统开发的背景 .......................................................................................................(1)二、系统剖析与设计 .......................................................................................................(2)三、系统的设计与实现 ...................................................................................................(一)设计初始化( Initialization) (2)(3)(二)设计编码( Encoding ) .......................................................................................(3)(三)设计译码( Decoding ) .......................................................................................(四)设计印代码文件( Print) (4)(五)设计印哈夫曼树( TreePrinting) (4)(5)四、系统测试 ...................................................................................................................(5)(一)测试 main 函数 .....................................................................................................(二)测试编码( Encoding )及译码( Decoding )函数 (5)(三)测试印代码文件( Print)函数 (6)(6)(四)测试有关的根目录 ................................................................................................(6)五、总结 ............................................................................................................................(7)六、附件(代码、部分图表) ........................................................................................哈夫曼编 / 译码器系统一、系统开发的背景为了提升信道利用率,缩短信息传输时间,降低传输成本,且在信息发送端经过一个编码系统对待传数据早先编码,在信息接收端将传来的数据进行译码(还原),所以设计哈夫曼编码/ 译码器系统。
哈夫曼编码译码器数据结构C语言
哈夫曼编码译码器数据结构C语言哈夫曼编码译码器数据结构C语言引言哈夫曼编码是一种用于无损数据压缩的编码方式,它利用出现频率较高的字符使用较短的编码,而出现频率较低的字符使用较长的编码。
通过这种方式可以使得编码后的数据占据较少的存储空间。
本文将介绍如何使用C语言实现一个哈夫曼编码译码器的数据结构。
哈夫曼树哈夫曼树是哈夫曼编码的关键数据结构,它可以通过给定的字符频率构建出一棵树。
在哈夫曼树中,每个字符都有一个对应的叶子节点,而非叶子节点表示编码的中间过程。
具体构建哈夫曼树的步骤如下:1. 统计每个字符的出现频率。
2. 将每个字符及其频率构建成一个节点,并按照频率从小到大排序。
3. 从频率最小的两个节点开始,合并成一个新节点,并将新节点的频率设为两个节点频率之和。
4. 将新节点插入到节点列表中,保持节点列表有序。
5. 重复步骤3和步骤4,直到只剩下一个节点,这个节点就是哈夫曼树的根节点。
编码在构建了哈夫曼树之后,我们可以根据树的结构来进行编码。
对于每个字符,其编码是由根节点到对应叶子节点路径上的边来表示的。
具体编码的步骤如下:1. 从根节点开始,递归遍历哈夫曼树的每个节点。
2. 如果当前节点为叶子节点,记录下从根节点到该叶子节点所经过的路径上的边的取值(0表示左边,1表示右边),得到该字符的编码。
3. 对于每个字符,将其编码存储起来以便后续使用。
译码译码的过程与编码相反,我们可以根据编码来找到对应的字符。
具体译码的步骤如下:1. 从哈夫曼树的根节点开始,逐个读取待译码的数据。
2. 如果读取的数据为0,移动到左子节点;如果读取的数据为1,移动到右子节点。
3. 如果移动到了叶子节点,记录下该叶子节点对应的字符,并回到根节点。
4. 重复步骤2和步骤3,直到读取完毕所有的数据,得到原始的字符序列。
实现下面是一个用C语言实现的哈夫曼编码译码器的数据结构示例:```cinclude <stdio.h>typedef struct Node {char character;int frequency;struct Node left;struct Node right;} Node;typedef struct HuffmanTree {Node root;} HuffmanTree;HuffmanTree buildHuffmanTree(char characters, int frequencies, int size) {// 构建哈夫曼树的代码实现}void encode(HuffmanTree tree, char string, char encodedString) {// 编码的代码实现}void decode(HuffmanTree tree, char encodedString, char decodedString) {// 译码的代码实现}int mn() {// 测试代码}```总结通过本文,我们了解了哈夫曼编码译码器的数据结构及其在C 语言中的实现。
哈夫曼编码译码器数据结构C语言
哈夫曼编码译码器数据结构c语言哈夫曼编码译码器数据结构目录1.引言1.背景2.目的3.范围2.哈夫曼编码概述1.哈夫曼树2.哈夫曼编码3.哈夫曼译码3.数据结构设计1.哈夫曼树结构2.编码表结构3.输入数据结构4.输出数据结构4.算法实现1.哈夫曼树构建算法2.编码表算法3.哈夫曼编码算法4.哈夫曼译码算法5.使用示例1.编码示例2.译码示例6.性能分析1.时间复杂度分析2.空间复杂度分析7.风险和限制1.输入数据限制2.输出数据限制3.算法限制8.附录1.示例代码2.测试数据3.参考文献1.引言1.1 背景哈夫曼编码是一种经典的数据压缩算法,通过构建哈夫曼树,将输入的数据进行编码。
哈夫曼编码的特点是可变长度编码,频率高的字符使用短编码,频率低的字符使用长编码。
1.2 目的本文档旨在详细介绍哈夫曼编码译码器的数据结构设计和算法实现,帮助读者理解和使用该编码器。
1.3 范围本文档涵盖了哈夫曼编码和译码的概述,数据结构设计,算法实现,使用示例以及性能分析。
2.哈夫曼编码概述2.1 哈夫曼树哈夫曼树是一种特殊的二叉树,用于构建哈夫曼编码。
它通过合并两个最小频率的节点来构建树,直到所有节点都被合并。
2.2 哈夫曼编码哈夫曼编码是将字符映射为可变长度的二进制码。
频率高的字符使用短码,频率低的字符使用长码。
编码表中保存了每个字符对应的编码。
2.3 哈夫曼译码哈夫曼译码是根据哈夫曼编码,将二进制码转换为原始字符。
3.数据结构设计3.1 哈夫曼树结构哈夫曼树的结构包含一个根节点和左右子节点。
```ctypedef struct huffmanTreeNode {char data; // 节点字符数据int frequency; // 节点字符出现的频率struct huffmanTreeNode left; // 左子节点指针struct huffmanTreeNode right; // 右子节点指针} huffmanTreeNode;```3.2 编码表结构编码表结构用于保存字符和对应编码的映射关系。
数据结构课程设计哈夫曼编码译码器
数据结构课程设计哈夫曼编码译码器个节点的权值、父节点、左孩子和右孩子,然后通过选择最小的两个节点合并,构建Huffman树;3:Huffman编码:通过遍历Huffman树,对每个叶子节点进行编码,将编码结果存入新的文件中;4:译码:读取存放Huffman编码的文件,通过遍历Huffman树进行译码,将译码结果存入新的文件中;5:结果验证:比较原文件和译码结果文件的内容是否一致,输出结果;3.函数说明1:CrtHuffmanTree():创建Huffman树;2:HuffmanCoding():对Huffman树进行遍历,生成Huffman编码;3:HuffmanDecoding():对Huffman编码进行译码,生成原文件内容;4:CompareFile():比较原文件和译码结果文件的内容是否一致;五、详细设计1.统计字符频率:定义结构体typedef struct strchar data;char num;str;其中data域存放字符名称,num域存放字符出现频率,读取文件ywq1.txt,通过循环比较将结果赋入S2[128]中;2.创建Huffman树:定义结构体typedef structchar data;int weight;int parent;int lchild;int rchild;HTNode,HuffmanTree[M+1];作为Huffman树存储节点类型,调用CrtHuffmanTree()函数,初始化各个节点的权值、父节点、左孩子和右孩子,然后通过选择最小的两个节点合并,构建Huffman树;3.Huffman编码:通过遍历Huffman树,对每个叶子节点进行编码,将编码结果存入新的文件中;4.译码:读取存放Huffman编码的文件,通过遍历Huffman树进行译码,将译码结果存入新的文件中;5.结果验证:比较原文件和译码结果文件的内容是否一致,输出结果;六、测试1.测试数据测试文件:ywq1.txt(包含英文字母、数字和符号)2.测试结果测试结果正确,能够正确地对文件进行Huffman编码和译码,生成的译码结果文件与原文件内容一致;七、总结通过本次课程设计,我深入了解了Huffman编码/译码器的实现原理和过程,掌握了Huffman树的创建、存储和遍历方法,提高了动手能力,同时也为数据压缩问题提供了一种有效的解决方法。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
哈夫曼编码译码器哈夫曼编码译码器学院班级: 信息工程学院软件1501 指导教师: 朱俊武小组成员: 刘洋蒋佳烨冀若含本人学号: 151303107 报告书写: 冀若含学生成绩:目录一、总体介绍·····························03-04二、详细设计·····························04-11三、运行测试·····························11-12四、课设总结·····························13-13五、附录代码·····························13-19一、总体介绍1.1任务概述我们小组做了两个版本,其中一个为文件操作版,另一个为键盘操作版。
两个版本都实现了哈夫曼编码/译码操做。
我主要负责的是构造哈夫曼树,给出各个字符的哈夫曼编码,加密操做,整个键盘操作版系统的代码重组、编辑。
开发的过程中使用了Codelite、Dev、Vc等软件。
参考书籍为《数据结构》(c语言版)。
其中文件操作版的具体实现为:○1能够实现对26个小写字母外加空格进行哈夫曼编码,并能够对一整篇文章(有小写字母和空格组成)进行加密,生成密码文件。
最后根据生成的密码翻译出原文并存档。
○2在使用程序时,使用者只需要对ToBetran文件进行原文的输入(使用小写字母或空格),加密和解密功能由程序自主来完成。
○3程序运行的过程中会输出进行编码的26个小写字母和空格(字符型),并输出其对应的权值(整型)。
还输出字符的编码及生成的密文。
最后输出解密后的原文。
键盘操作版为:○1要求从键盘输入字符集和字符的权值,大部分字符均可输入,需要各个字符的权值不能相同。
○2利用输入的权值建立哈夫曼树,得到每个字符的前缀编码。
○3输入字符串,程序对其进行加密。
○4输入密文(1010101……………..)对密文进行解密。
两个版本都利用了哈夫曼树解决问题,通过建立哈夫曼树,得出每个字符的独特前缀编码,也就是密文,然后利用密文对明文进行加密得到密文。
密文转换为明文则是通过对哈夫曼树的遍历。
(之前想开始构建哈夫编码译码曼树本系统的实现难点在于哈夫曼树的构造。
编码、译码功能的实现都是基于哈夫曼树的。
二、详细设计2.1哈夫曼树的构造哈夫曼树,又称最优树,是一类带权路径长度最短的树,有着广泛的应用。
哈夫曼树的构造过程如下:1.初始化:根据给定的n个权值{w1,w2,…wn}构成n棵二叉树的集合F={T1,T2,..,Tn},其中每棵二叉树Ti中只有一个带权wi的根节点,左右子树均空。
2. 找最小树:在F中选择两棵根结点权值最小的树作为左右子树构造一棵新的二叉树,且至新的二叉树的根结点的权值为其左右子树上根结点的权值之和。
3. 删除与加入:在F中删除这两棵树,并将新的二叉树加入F中。
4. 判断:重复前两步(2和3),直到F中只含有一棵树为止。
该树即为哈夫曼树。
2.2 代码实现哈夫曼树和哈夫曼编码的储存表示typedef struct{int weight;int parent,lchild,rchild;}HTNode,*HuffmanTree;//动态分配数组储存哈夫曼树typedef char* *HuffmanCode;//动态分配数组储存哈夫曼编码表void Select(HuffmanTree HT,int p,int *s1,int *s2)该函数的功能为:找出HT[1….i-1]中parent为0且weight最小的两个结点,其序号为s1,s2。
void HuffmanCoding(HuffmanTree HT,HuffmanCode HC,int *w,int n,char *a)该函数的功能为构造哈夫曼树HT,并求出n个字符的哈夫曼编码HC。
以下为两个函数的流程图或详细设计。
void HuffmanCoding(HuffmanTree HT,HuffmanCode HC,int *w,int n,char *a)M=2*n-1开始为HT申请长度为m+1的内存空间给HT数组的前n个赋值为{*w,0,0,0}给HT数组的后n-1个赋值为{0,0,0,0}i=n+1Select()HT[s1].parent=IHt[s2].parent=I;Ht[i],lchild=s1;Ht[i].rchild=s2;Ht[i].weight=HT[s1].weight +HT[s2].weight;i++;i<=m?YN weiHC指针分配空间小。
注:具体程序中加入了输出各个字符的哈夫曼编码的功能,在流程图没有显示。
没画完下面还有哟!!!!weiHC指针分配空间为cd分配纯储存空间Cd[n-1]=\0 i=1 Start=n-1C=IF=HT[I].PARENTHT[F].LCHILD==CYCD[--START]=0'NCd[--start]=1';C=f,f=HT[f].parentF!=0?YN为第i个字符分配空间复制cd到HCi<=N?N Free(cd)Yvoid *a){ int m=0;int c;int f;int start;char *cd;int *s1;int *s2;int i;s1=(int*)malloc(sizeof(int));s2=(int*)malloc(sizeof(int));m=2*n-1;if(n<=1){printf("字符的个数过少\n");return;}HuffmanTree p;p=HT;p++;for(i=1;i<=n;++i,++p,++w){p->weight=*w;p->parent=0;p->lchild=0;p->rchild=0;}for(;i<=m;++i,++p){p->weight=0;p->parent=0;p->lchild=0;p->rchild=0;}for(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;}cd=(char *)malloc(n*sizeof(char));cd[n-1]='\0';for(i=1;i<=n;++i){start=n-1;for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent)if(HT[f].lchild==c) cd[--start]='0';else cd[--start]='1';HC[i]=(char *)malloc((n-start)*sizeof(char));strcpy(HC[i],&cd[start]);printf("%c ",*a);a++;printf("%s\n",HC[i]);}free(cd);}void Select(HuffmanTree HT,int p,int *s1,int *s2)详细设计:○1首先通过一个循环找出当前数组中weight最小的一个。
记录下它的序号。
○2也是一和一样的循环和算法。
加上一个if语句,如果循环到与第一次序号一样的那次,就continue跳过这次比较。
○3将得到的权值最小的两个传到s1和是s2指向的地址。
这就是哈夫曼树的构造和生成哈夫曼编码的过程。
详细代码:void Select(HuffmanTree HT,int p,int *s1,int *s2)//i为遍历长度{int i=1;int x=0;int y=0;int min=1000;int min1=1000;int v=1;*s1=1;*s2=1;for(i=1;i<=p;i++){x=HT[i].parent;y=HT[i].weight;if(x==0&&min>y){min=HT[i].weight;*s1=i;v=i;}}for(i=1;i<=p;i++){x=HT[i].parent;y=HT[i].weight;if(i==v)continue;if(x==0&&min1>=y){min1=HT[i].weight;*s2=i;}}}2.3 编码(加密)void HuffmanEncryption(HuffmanCode HC,char *a,int n)此函数开始从键盘读入要加密的字符串i=0J=0Input[i]==a[j]Y输出HC[j+1]J++NJ<NYNI++I<LONY结束码在不同数组的对应关系,进行加密。