内容:

从键盘接收一串电文字符,输出对应的Huffman(哈夫曼)编码,同时,能翻译由Huffman编码生成的代码串,输出对应的电文字符串。设计要求:

(1)构造一棵Huffman树;

        (2)实现Huffman编码,并用Huffman编码生成的代码串进行译码;

        (3)程序中字符串和权值是可变的,实现程序的灵活性。

步骤:

1.算法分析:

在电报通信中,电文是以二进制代码传送的。在发送时,需要将电文中的字符转换成二进制代码串,即编码;在接收时,要将收到的二进制代码转化为对应的字符序列,即译码。由于字符集中的字符被使用的频率是非均匀的,在传送电文时,要想使电文的总长尽可能短。因此,若对某字符集进行不等长的编码设计,则要求任意一个字符的编码都不是其他字符编码的前缀,这种编码称作前缀编码由Huffman树求得的编码是最优的缀码,也叫Huffman编码。给出字符集和各个字符的概率分布,构造Huffman树,将Huffman树中每个分支结点的左分支标为0,将根到每个叶子路径上的标号连起来,就是该叶子所代表字符的编码。

数据结构:本设计使用结构体数组存储Huffman树。

算法设计:

程序中设计了两个函数:

(1)函数HuffmanTree()用来构造Huffman树;

    (2)函数HuffmanCode()用来生成Huffman编码并输出。

程序中主函数根据提示输入一些字符和字符的权值,则程序输出哈夫曼编码;若输入电文,则可以输出哈夫曼译码。

1.构造Huffman树的算法

主程序中输入不同字符,统计不同字符出现的次数作为该字符的权值,存于data[]数组中。假设有n中字符,则有n个叶子节点,构造的哈夫曼树有2n-1个结点。具体步骤如下:

(1)将n个字符(叶结点)和其他权值存储在HuffNode数组的前n个数组元素中;将2n-1个结点的双亲和左右孩子均置-1.

      (2)在所有结点中,选择双亲为-1,并选择具有最小和次小权值的结点m1和m2,用x1和x2指示这两个结点在数组中的位置,将根为HuffNode[x1]和HuffNode[x2]的两棵树合并,使其成为新结点HuffNode[n+i]的左右孩子,其权值为m1+m2。

(3)重复上述过程,共进行n-1次合并就构造了一棵Huffman树,产生的n-1个结点依次放在数组HuffNode[]的n-2n-2的单元中。

在构造哈夫曼树时,可以设置一个结构数组HuffNode保存哈夫曼树中个结点的信息,根据二叉树的性质可知,具有n个叶子结点的哈夫曼树共有2n-1个结点,所以数组HuffNode的大小设置为2n-1,数组元素的构造形式如下:

     weight     lchild     rchild   parent

其中,weight域保存结点的权值,lchild和rchild域分别保存该结点的左、右孩子结点在数组HuffNode中的序号,从而建立起结点之间的关系。为了判定一个结点是否已加入到要建立的哈夫曼树中,可通过parent域的值来确定。初始时parent的值为-1,当结点是否已加入到树中时,该结点parent的值为其双亲结点在数组HuffNode中的序号,就不会是-1了。

构造哈夫曼树时,首先将由n个字符形成的n个叶结点存放到数组HuffNode的前n个分量中,然后根据前面介绍的哈夫曼方法的基本思想,不断将两个小子树合并为一个较大的子树,每次构成的新子树的根节点顺序放到HuffNode数组中的后面n-1个分量。

构造算法如下:

#define MAXVALUE 10000
#define MAXLEAF 30
#define MAXNODE MAXLEAF*2-1
typedef struct node{char letter;int weight;               //结点的权值 int parent;               //结点的双亲 int lchild;               //结点的左孩子 int rchild;              //结点的右孩子
}HNodeType;
//哈夫曼树的构造算法
void HuffmanTree(HNodeType HuffNode[],int n,Message a[])
{int i,j,m1,m2,x1,x2,temp1;char temp2;for(i=0;i<2*n-1;i++)  //HuffNode[]初始化{HuffNode[i].letter=NULL;HuffNode[i].weight=0;HuffNode[i].parent=-1;HuffNode[i].lchild=-1;HuffNode[i].rchild=-1;} for(i=0;i<n-1;i++)for(j=i+1;j<n-1;j++)if(a[j].num>a[i].num){temp1=a[i].num;a[i].num=a[j].num;a[j].num=temp1;temp2=a[i].s;a[i].s=a[j].s;a[j].s=temp2;}for(i=0;i<n;i++){HuffNode[i].weight=a[i].num;HuffNode[i].letter=a[i].s;}for(i=0;i<n-1;i++)   //构造哈夫曼树{m1=m2=MAXVALUE;x1=x2=0;for(j=0;j<n+i;j++)  //找出的两棵权值最小的子树{if(HuffNode[j].parent==-1&&HuffNode[j].weight<m1){m2=m1;x2=x1;m1=HuffNode[j].weight;  x1=j;}else if(HuffNode[j].parent==-1&&HuffNode[j].weight<m2){m2=HuffNode[j].weight;x2=j;}} //将找出的两棵子树合并为一棵子树HuffNode[x1].parent=n+i;HuffNode[x2].parent=n+i;HuffNode[n+i].weight=HuffNode[x1].weight+HuffNode[x2].weight;HuffNode[n+i].lchild=x1;HuffNode[n+i].rchild=x2; } } 

2.Huffman编码和译码的算法

求哈夫曼编码,实质上就是在已建立的哈夫曼树中,从叶结点开始,沿双亲的双亲链域回退到根节点,每回退一步,就走过了哈夫曼树的一个分支,从而得到一位哈夫曼码值,由于一个字符的哈夫曼编码是从根节点到相应叶结点所经过的路径上各分支所组成的0、1序列,因此先得到的分支码为所求编码的低位码,后得到的分支码为所求编码的高位码。我们可以设置一结构数组HuffCode用来存放各字符的哈夫曼编码信息,数组元素的结构如下:

           bit         start

其中,分量bit为一维数组,用来保存字符的哈夫曼编码,start表示该编码在数组bit中的开始位置。所以,对于第i个字符,它的哈夫曼编码存放在HuffCode[i].bit中的从HuffCode[i].start到n的分量上。

(1)从Huffman树的叶子结点HuffNode[i](0<=i<n)出发,通过HuffNode[c].parent找到双亲,通过lchild和rchild域可知HuffNode[c]是左分支还是右分支,若是左分支则bit[n-1-i]=0;否则bit[n-1-i]=1.

        (2)将HuffNode[c]作为出发点,重复上述过程,直到找到树根位置,即进行了Huffman编码

        (3)译码时首先输入二进制代码串,放在数组code中,以回车结束输入。

       (4)将代码与编码进行比较,如果为0,则转向左子树;如果为1,则转向右子树,直到叶结点结束。输出叶子结点的数据域,即所对应的字符。

哈夫曼编码的实例如下:

#define MAXBIT 50
typedef struct{char letter;int bit[MAXBIT];int start;
}HCodeType;
//生成哈夫曼编码void HuffmanCode(int n,Message a[]){HNodeType HuffNode[MAXNODE];HCodeType HuffCode[MAXLEAF],cd;int i,j,c,p;char code[30],*m;HuffmanTree(HuffNode,n,a);  //建立哈夫曼树for(i=0;i<n;i++){cd.start=n-1;c=i;p=HuffNode[c].parent;while(p!=-1)    //由叶结点向上直到树根{if(HuffNode[p].lchild==c)cd.bit[cd.start]=0;elsecd.bit[cd.start]=1;cd.start--;c=p;p=HuffNode[c].parent;} for(j=cd.start+1;j<n;j++)  //保存求出的每个结点的哈夫曼编码和编码的起始位HuffCode[i].bit[j]=cd.bit[j];HuffCode[i].start=cd.start; } printf("输出每个叶子的哈夫曼编码:\n");for(i=0;i<n;i++)    //输出每个叶子结点的哈夫曼编码 {HuffCode[i].letter=HuffNode[i].letter;printf(" %c:",HuffCode[i].letter);for(j=HuffCode[i].start+1;j<n;j++)printf(" %d",HuffCode[i].bit[j]);printf("\n"); }
}

接下来举一个实例,说明一下哈夫曼编码:

下面是一串字符:abbcddd的编码结果:

根据出现的频率分别给其赋权值:a:1  b:2  c:1  d:3

根据哈夫曼树给其编码,现在输入电文:01011000111。则可输出译码:dbaddc.

2.概要设计:

使用C语言,使用的主要函数如下:

                           函数                      作用
                HuffmanTree()        用来构造一个Huffman树
                HuffmanCode()    用来生成Huffman编码并输出

3.程序运行流程图:

4.实例运行结果:

5.总结

用哈夫曼树进行编码,不会产生二义性的问题,而且哈夫曼编码是一种能使电文代码总长最短的不等长编码,非常的巧妙。哈夫曼编码也是最基本的压缩编码的方法,对于以后学习也很重要。

6.源代码(Dev-c++ 5.11,vc++6.0编译通过):

#include<stdio.h>
#include<conio.h>
#define MAXVALUE 10000           //定义最大权值
#define MAXLEAF 30               //定义哈夫曼树中叶子节点个数
#define MAXNODE MAXLEAF*2-1
#define MAXBIT 50
#define NULL 0
typedef struct node{char letter;int weight;               //结点的权值 int parent;               //结点的双亲 int lchild;               //结点的左孩子 int rchild;              //结点的右孩子
}HNodeType;
typedef struct{char letter;int bit[MAXBIT];int start;
}HCodeType;
typedef struct{char s;int num;
}Message;
//哈夫曼树的构造算法
void HuffmanTree(HNodeType HuffNode[],int n,Message a[])
{int i,j,m1,m2,x1,x2,temp1;char temp2;for(i=0;i<2*n-1;i++)  //HuffNode[]初始化{HuffNode[i].letter=NULL;HuffNode[i].weight=0;HuffNode[i].parent=-1;HuffNode[i].lchild=-1;HuffNode[i].rchild=-1;} for(i=0;i<n-1;i++)for(j=i+1;j<n-1;j++)if(a[j].num>a[i].num){temp1=a[i].num;a[i].num=a[j].num;a[j].num=temp1;temp2=a[i].s;a[i].s=a[j].s;a[j].s=temp2;}for(i=0;i<n;i++){HuffNode[i].weight=a[i].num;HuffNode[i].letter=a[i].s;}for(i=0;i<n-1;i++)   //构造哈夫曼树{m1=m2=MAXVALUE;x1=x2=0;for(j=0;j<n+i;j++)  //找出的两棵权值最小的子树{if(HuffNode[j].parent==-1&&HuffNode[j].weight<m1){m2=m1;x2=x1;m1=HuffNode[j].weight;  x1=j;}else if(HuffNode[j].parent==-1&&HuffNode[j].weight<m2){m2=HuffNode[j].weight;x2=j;}} //将找出的两棵子树合并为一棵子树HuffNode[x1].parent=n+i;HuffNode[x2].parent=n+i;HuffNode[n+i].weight=HuffNode[x1].weight+HuffNode[x2].weight;HuffNode[n+i].lchild=x1;HuffNode[n+i].rchild=x2; } } //生成哈夫曼编码void HuffmanCode(int n,Message a[]){HNodeType HuffNode[MAXNODE];HCodeType HuffCode[MAXLEAF],cd;int i,j,c,p;char code[30],*m;HuffmanTree(HuffNode,n,a);  //建立哈夫曼树for(i=0;i<n;i++){cd.start=n-1;c=i;p=HuffNode[c].parent;while(p!=-1)    //由叶结点向上直到树根{if(HuffNode[p].lchild==c)cd.bit[cd.start]=0;elsecd.bit[cd.start]=1;cd.start--;c=p;p=HuffNode[c].parent;} for(j=cd.start+1;j<n;j++)  //保存求出的每个结点的哈夫曼编码和编码的起始位HuffCode[i].bit[j]=cd.bit[j];HuffCode[i].start=cd.start; } printf(" 输出每个叶子的哈夫曼编码:\n");for(i=0;i<n;i++)    //输出每个叶子结点的哈夫曼编码 {HuffCode[i].letter=HuffNode[i].letter;printf(" %c:",HuffCode[i].letter);for(j=HuffCode[i].start+1;j<n;j++)printf(" %d",HuffCode[i].bit[j]);printf("\n"); }printf(" 请输入电文(1/0):\n");for(i=0;i<30;i++)code[i]=NULL;scanf(" %s",&code); m=code;c=2*n-2;printf(" 输出哈夫曼译码:\n");while(*m!=NULL){if(*m=='0'){c=i=HuffNode[c].lchild;if(HuffNode[c].lchild==-1&&HuffNode[c].rchild==-1){printf("%c",HuffNode[i].letter);c=2*n-2;}}if(*m=='1'){c=i=HuffNode[c].rchild;if(HuffNode[c].lchild==-1&&HuffNode[c].rchild==-1){  printf("%c",HuffNode[i].letter);c=2*n-2;}}m++;} printf("\n");}
void main(){Message data[30];char s[100],*p;int i,count=0;printf("\n 请输入一些字符:");scanf("%s",&s);for(i=0;i<30;i++){data[i].s=NULL;data[i].num=0;} p=s;while(*p){for(i=0;i<=count+1;i++){if(data[i].s==NULL){data[i].s=*p;data[i].num++;count++;break;}else if(data[i].s==*p){data[i].num++;break;}}p++;}printf("\n");printf(" 不同的字符数:%d\n",count);for(i=0;i<count;i++){  printf(" %c ",data[i].s);printf(" 权值:%d",data[i].num);printf("\n");}HuffmanCode(count,data);getch();}

电文的编码和译码,哈夫曼编码译码(C语言)相关推荐

  1. 可逼近信道容量编码技术之霍夫曼编码的实现

    可逼近信道容量编码技术之霍夫曼编码的实现 简介 在当今信息爆炸时代,如何采用有效的数据压缩技术来节省数据文件的存储空间和计算机网络的传送时间已越来越引起人们的重视.哈夫曼编码正是一种应用广泛且非常有效 ...

  2. 计算机编码问题总结——哈夫曼编码

    我是荔园微风,作为一名在IT界整整25年的老兵,今天总结一下计算机中的编码问题,来看第四部分,哈夫曼编码. 哈夫曼树,又叫霍夫曼树.最优二叉树,表示带权路径最短的树,什么意思呢,没听懂...... 唉 ...

  3. labview霍夫曼编码_为什么霍夫曼编码好?

    7 个答案: 答案 0 :(得分:3) 如果为最常用使用的符号指定较少的数字或位或较短的代码字词,则可以节省大量存储空间. 假设您要为英文字母分配26个唯一代码,并希望根据这些代码存储英文小说(仅限字 ...

  4. 创建霍夫曼树,霍夫曼编码以及使用霍夫曼编码压缩文件

    那么,什么是霍夫曼树(赫夫曼树)呢? 给定n个权值(权值就是每个节点里面存放的数据,但是根据业务需求不同,存放的数据类型有些差别)作为n个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样 ...

  5. 霍夫曼编码实验matlab,哈夫曼编码 MATLAB程序

    clc clear fid=fopen( 'C:\Users\yichao\Desktop\新建文本文档.txt');%打开 txt 文件 [zimu]=fscanf(fid, '%c'); %读取二 ...

  6. 【算法学习笔记】哈夫曼树的构建和哈夫曼编码的实现代码

    介绍 哈夫曼(Haffman)这种方法的基本思想如下: ①由给定的n个权值{W1,W2,-,Wn}构造n棵只有一个叶子结点的二叉树,从而得到一个二叉树的集合F={T1,T2,-,Tn}. ②在F中选取 ...

  7. 哈夫曼编码算法 c语言,《哈夫曼编码的算法》

    以前的作业,拿出来看看,都不会了.郁闷 记得当时为了完成这作业,求了一圈朋友,最后还是在图书馆网络中找的!呵呵!在这里晒晒了 设计报告内容: 一. 课程设计名称 <哈夫曼编码的算法> 二. ...

  8. 哈夫曼java_哈夫曼树和哈夫曼编码介绍以及Java实现案例

    1.哈夫曼树 1.1哈夫曼树简介 哈夫曼树:给定N个权值作为N个叶子节点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree).哈夫曼树 ...

  9. 哈夫曼树及哈夫曼编码

    哈夫曼树 哈夫曼树,最优二叉树,带权路径长度(WPL)最短的树.它没有度为1的点,是一棵严格的二叉树(满二叉树). 何谓'带权路径长度' 了解哈夫曼树,我们首先要知道树的几个相关术语,并了解什么是WP ...

  10. 信息论与编码_哈夫曼编码

    哈夫曼树 哈夫曼树(Huffman Tree)也是一种特殊的二叉树,这种树的所有叶子结点都带有权值,从中构造出带权路径长度最短的二叉树,即哈夫曼树. 哈夫曼树的定义 ​ 设二叉树具有n个带权值的叶子结 ...

最新文章

  1. Android libcutils库中整数溢出导致的堆破坏漏洞的发现与利用
  2. OpenCV添加(混合)两个图像
  3. 为啥用redis解决会话呢?
  4. Vmware工作笔记-通过光驱位与虚拟机(Vmware)共享数据【含iso制作】
  5. K-近邻算法(KNN)概述
  6. bundler for jekyll
  7. Bootstrap简洁、直观、强悍的前端开发框架
  8. 全面分析网络安全防御
  9. 【高等数学】微积分----教你如何简单地推导求导公式(一)
  10. 金山词霸2009牛津with SP3完全破解版(含全部本地词库和语音包)
  11. java指纹读取_Microsoft指纹读取器-迷你评论
  12. 用python做下拉菜单
  13. 业聚医疗在港交所上市:市值约76亿港元,钱永勋、刘桂祯夫妇控股
  14. 抖音通过什么方式变现,抖音变现方式分别有什么
  15. 如何快速建立一个优秀的账号体系
  16. 德州仪器TM4C123GXL从入手到亮灯-开发环境配置
  17. 关于Oracle索引的一点认识
  18. 数字集成电路设计-12-状态机的四种写法
  19. Python——生成激活码并存入MySQL
  20. 解决Origin导出图片失真问题

热门文章

  1. 8年java_一个8年Java程序员的年终总结,献给还在迷茫中的你
  2. RN图表组件react-native-charts-wrapper
  3. 专业知识和计算机思维的关系是什么意思,什么是计算机思维?
  4. C++ 原子操作 atomic 的一些思考
  5. nginx做本地目录 映射
  6. Linux命令行如何查看cpu(lm_sensors)和显卡温度(nvidia-smi)
  7. Android SDK Manager资源下载
  8. vmospro启动黑屏_VMOS Pro,安卓手机上的虚拟机
  9. 如何激发孩子的想象力_如何正确引导孩子的想象力
  10. 河北科技大学和河北工程大学计算机哪个好,理工学院客观对比:河北科大和河北工程大学哪所好?...