最近完成了数据结构课程设计,被分到的题目是《哈夫曼编码和解码》,现在在这篇博文里分享一下自己的成果。

  我在设计时,在网上参考了很多老师和前辈的算法和代码,向他们表示感谢!他们的成果给了我很多启示和帮助。另外,自己的成品中也还有很多不完善的地方,欢迎批评指正。

课题:哈夫曼编码与解码 C++代码实现

(1)统计某电文中字符出现的频率(假设电文中只含有大小写英文字母,以及逗号和点号);
(2)把字符出现的频率作为权值建立哈夫曼树,进行哈夫曼编码,并输出每个字符的编码结果;
(3)对电文进行哈夫曼编码;
(4)把电文的哈夫曼编码进行译码,输出对应电文的内容。

 #include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <ctype.h>
#define MAX 999999 //一个极大值
#define NUM 10 //存储哈夫曼树每个结点
typedef struct Node {
char ch;
int weight; //权值
int parent;
int lchild,rchild;
}HFNode;
//存储每个字符及其哈夫曼编码
typedef struct {
char ch;
char code[NUM];
}HFCharCode; HFNode HT[*-]; //哈夫曼树结构体
HFCharCode HCD[]; //哈夫曼编码结构体
int LeafNum; //叶子结点数
int NodeNum; //所有结点数
char EnterStr[MAX]; //输入的待编码电文
char EnterCode[MAX]; //输入的待解码密文
char RealStr[MAX]; //密文解码后的电文
int AllWeight[]; //存储所有28个字符的权值 void Statistics();
void CreateHFTree();
void SelectMin(int &min1, int &min2);
void CreateHFCode();
void ReverseStr(char *str);
void EncodeStr();
void DecodeHFCode(); int main() {
printf("****** 哈夫曼编码与解码 ******\n\n");
printf("*** 输入一串字符串 ***\n");
scanf("%s", EnterStr);
getchar();
Statistics();
CreateHFTree();
CreateHFCode();
EncodeStr();
printf("\n*** 输入想解码的内容 ***\n");
scanf("%s", EnterCode);
getchar();
DecodeHFCode();
return ;
} //统计每个字符权值
void Statistics() {
int len = strlen(EnterStr);
for(int i = ; i <= ; i++)
AllWeight[i] = ;
for(int j = ; j <= len - ; j++) {
if(isalpha(EnterStr[j])) {
EnterStr[j] = tolower(EnterStr[j]);
AllWeight[EnterStr[j]-'a']++;
}
else if((int)EnterStr[j] == )
AllWeight[]++;
else if((int)EnterStr[j] == )
AllWeight[]++;
else {
printf("\n输入不符合要求!\n\n");
exit(-);
}
}
int i = , j = ;
for( ; i <= ; i++) {
if(AllWeight[i] != ) {
HT[j].weight = AllWeight[i];
HT[j].ch = i+'a';
j++;
}
}
if(AllWeight[i] != ) {
HT[j].weight = AllWeight[i];
HT[j].ch = ',';
j++;
i++;
}
if(AllWeight[i] != ) {
HT[j].weight = AllWeight[i];
HT[j].ch = '.';
}
printf("\n*** 打印每个字符的权值 ***\n");
int n = ;
for(int i = ; i <= ; i++) {
if(AllWeight[i] != ) {
n++;
if(i <= )
putchar('a'+i);
else if(i == )
printf(",");
else
printf(".");
printf(": %d\n", AllWeight[i]);
}
}
LeafNum = n;
NodeNum = *LeafNum-;
} //构造哈夫曼树
void CreateHFTree() {
int i;
for(i = ; i <= LeafNum-; i++) {
HT[i].parent = -;
HT[i].lchild = -;
HT[i].rchild = -;
HT[i].weight = HT[i].weight;
}
for(; i <= NodeNum-; i++) {
HT[i].parent = -;
HT[i].lchild = -;
HT[i].rchild = -;
HT[i].weight = MAX;
}
int min1, min2;
for(i = LeafNum; i <= NodeNum-; i++) {
SelectMin(min1, min2);
HT[min1].parent = i;
HT[min2].parent = i;
HT[i].lchild = min1;
HT[i].rchild = min2;
HT[i].weight = HT[min1].weight + HT[min2].weight;
}
// printf("\n*** 打印哈夫曼树 ***\n");
// for(int i = 0; i <= NodeNum-1; i++) {
// printf("序号:%d 字符:%c 权值:%d 双亲:%d 左孩:%d 右孩:%d\n", i, HT[i].ch, HT[i].weight, HT[i].parent, HT[i].lchild, HT[i].rchild);
// }
}
//找到两个权值最小的二叉树的序号
void SelectMin(int &min1, int &min2) {
int i = ;
int temp;
int wetmin1, wetmin2;
while(HT[i].parent != -)
i++;
wetmin1 = HT[i].weight;
min1 = i;
i++;
while(HT[i].parent != -)
i++;
wetmin2 = HT[i].weight;
min2 = i;
i++;
if(wetmin1 > wetmin2) {
temp = wetmin2;
wetmin2 = wetmin1;
wetmin1 = temp;
temp = min2;
min2 = min1;
min1 = temp;
}
for(; i <= NodeNum-; i++) {
if(HT[i].weight < wetmin1 && HT[i].parent == -) {
wetmin2 = wetmin1;
wetmin1 = HT[i].weight;
min2 = min1;
min1 = i;
} else if(HT[i].weight < wetmin2 && HT[i].parent == -) {
wetmin2 = HT[i].weight;
min2 = i;
}
}
} //进行哈夫曼编码
void CreateHFCode() {
int i, j, len;
for(i = ; i <= LeafNum-; i++) {
len = ;
j = i;
HCD[i].ch = HT[j].ch;
while(HT[j].parent != -) { //不是根节点
if(HT[HT[j].parent].lchild == j) { //是双亲结点的左孩子
HCD[i].code[len++] = ''+; //加上字符0
}else //是右孩子
HCD[i].code[len++] = ''+; //加上字符1
j = HT[j].parent; //往上遍历
}
HCD[i].code[len] = '\0'; //字符串末尾
ReverseStr(HCD[i].code);
}
printf("\n*** 打印每个字符的编码 ***\n");
for(int i = ; i <= LeafNum-; i++)
printf("%c: %s\n", HT[i].ch, HCD[i].code);
}
//将一个字符串反转
void ReverseStr(char *str) {
int i, j;
char c;
for(i = , j = strlen(str)-; i < j; i++, j--) {
c = str[i];
str[i] = str[j];
str[j] = c;
}
} //哈夫曼编码
void EncodeStr() {
int len = strlen(EnterStr);
printf("\n*** 编码结果 ***\n");
for(int i = ; i <= len-; i++) {
for(int j = ; j <= LeafNum-; j++) {
if(EnterStr[i] == HCD[j].ch)
printf("%s", HCD[j].code);
}
}
printf("\n");
} //哈夫曼解码
void DecodeHFCode() {
int k = NodeNum-; //根结点序号, 开始时一定在最后一个
int len = , i = ;
while(EnterCode[i]) {
if(EnterCode[i] == ''+)
k = HT[k].lchild;
else if(EnterCode[i] == ''+)
k = HT[k].rchild;
else {
printf("\n错误! 密文中仅能含有1和0!\n\n");
exit(-);
}
if(HT[k].lchild == - && HT[k].rchild == -) {
RealStr[len++] = HT[k].ch;
k = NodeNum-;
}
i++;
}
RealStr[len] = '\0';
if(k == NodeNum-) {
printf("\n*** 解码结果 ***\n%s\n\n", RealStr);
exit();
}
printf("\n错误! 部分密文无法解密!\n\n");
exit(-);
}

哈夫曼编码与解码的C++实现:建立哈夫曼树、进行哈夫曼编码与解码的更多相关文章

  1. 【视频编解码·学习笔记】7. 熵编码算法:基础知识 & 哈夫曼编码

    一.熵编码概念: 熵越大越混乱 信息学中的熵: 用于度量消息的平均信息量,和信息的不确定性 越是随机的.前后不相关的信息,其熵越高 信源编码定理: 说明了香农熵越信源符号概率之间的关系 信息的熵为信源 ...

  2. c++实现哈夫曼树,哈夫曼编码,哈夫曼解码(字符串去重,并统计频率)

    #include <iostream> #include <iomanip> #include <string> #include <cstdlib> ...

  3. [数据结构与算法]哈夫曼(Huffman)树与哈夫曼编码

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  4. Java数据结构(十二)—— 霍夫曼树及霍夫曼编码

    霍夫曼树 基本介绍和创建 基本介绍 又称哈夫曼树,赫夫曼树 给定n个权值作为n个叶子节点,构造一棵二叉树,若该树的带权路径长度(wpl)达到最小,称为最优二叉树 霍夫曼树是带权路径长度最短的树,权值较 ...

  5. 哈夫曼(huffman)树和哈夫曼编码

    哈夫曼树 哈夫曼树也叫最优二叉树(哈夫曼树) 问题:什么是哈夫曼树? 例:将学生的百分制成绩转换为五分制成绩:≥90 分: A,80-89分: B,70-79分: C,60-69分: D,<60 ...

  6. 数据结构图文解析之:哈夫曼树与哈夫曼编码详解及C++模板实现

    0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...

  7. 哈夫曼(Huffman)树和哈夫曼编码

    一.哈夫曼(Huffman)树和哈夫曼编码 1.哈夫曼树(Huffman)又称最优二叉树,是一类带权路径长度最短的树, 常用于信息检测. 定义: 结点间的路径长度:树中一个结点到另一个结点之间分支数目 ...

  8. Java 树结构实际应用 二(哈夫曼树和哈夫曼编码)

     赫夫曼树 1 基本介绍 1) 给定 n 个权值作为 n 个叶子结点,构造一棵二叉树,若该树的带权路径长度(wpl)达到最小,称这样的二叉树为 最优二叉树,也称为哈夫曼树(Huffman Tree), ...

  9. 【视频编解码·学习笔记】8. 熵编码算法:基本算法列举 & 指数哥伦布编码

    一.H.264中的熵编码基本方法: 熵编码具有消除数据之间统计冗余的功能,在编码端作为最后一道工序,将语法元素写入输出码流 熵解码作为解码过程的第一步,将码流解析出语法元素供后续步骤重建图像使用 在H ...

  10. java实现哈弗曼树和哈夫曼树压缩

    本篇博文将介绍什么是哈夫曼树,并且如何在java语言中构建一棵哈夫曼树,怎么利用哈夫曼树实现对文件的压缩和解压.首先,先来了解下什么哈夫曼树. 一.哈夫曼树 哈夫曼树属于二叉树,即树的结点最多拥有2个 ...

随机推荐

  1. 正则表达式-Csharp

    原文:正则表达式-Csharp 学习笔记:正则表达式 一. 正则表达式 正则表达式(Regex)是用来进行文本处理的技术,是语言无关的,在几乎所有语言中都有实现. 一个正则表达式就是由普通的字符及特殊 ...

  2. 利用shell脚本实现计划任务功能 V1.2

    2013.05.10  mytask 1.2 主程序休眠时间分成若干小的时间片断分段休眠,避免长时间的休眠不能及时响应系统信号. 2013.05.07 mytask 1.1 昨天发布了mytask1. ...

  3. SimpleMembershipProvider 的 MySql 实现

    认 证我一直用的是微软的 Membership 体系,看 MySql 也实现了对应的 Provider,在新建立了一个 MVC4 项目后,把 Provider 一改就直接启动,然后就出错了.异常是“T ...

  4. Python中的参数传递问题

    首先需要说明python中元组,列表,字典的区别. 列表: 什么是列表呢?我觉得列表就是我们日常生活中经常见到的清单. 例如:lst = ['arwen',123] 向list中添加项有两种方法:ap ...

  5. UITableViewStyleGrouped 设置表头出现section不为0的问题

    UITableViewStyleGrouped 设置表头出现section不为0的问题 1.如果使用UITableViewStylePlain样式的表格,那么header是会在表格滑动的时候在顶部悬浮 ...

  6. Memcached在Linux系统下的安装和PHP开启 Memcached的 扩展 超级解决方案

    [项目背景]:阿里云ECS服务器,Linux(centos7.2 64位),环境部署使用的是阿里云一键安装包(LAMP)等 [项目需求]:linux安装memcached 和php开启Memcache ...

  7. Linux虚拟机没有IP的解决办法

    这里之所以是查看下IP ,是我们后面要建一个Centos远程工具Xshell 连接Centos的时候,需要IP地址,所以我们这里先 学会查看虚拟机里的Centos7的IP地址 首先我们登录操作系统 用 ...

  8. 代码审计之seacms v6.45 前台Getshell 复现分析

    1.环境: php5.5.38+apache+seacms v6.45 seacms目录结构: │─admin //后台管理目录 │ │─coplugins //已停用目录 │ │─ebak //帝国 ...

  9. SpringBoot从入门到精通十一(SpringBoot文件上传的两种方法)

    前言 在企业级项目开发过程中,上传文件是最常用到的功能.SpringBoot集成了SpringMVC,当然上传文件的方式跟SpringMVC没有什么出入. 本章目标 使用SpringBoot项目完成单 ...

  10. Redis 在java中的使用(登录验证,5分钟内连续输错3次密码,锁住帐号,半小时后解封)(三)

    在java中使用redis,做简单的登录帐号的验证,使用string类型,使用redis的过期时间功能 1.首先进行redis的jar包的引用,因为用的是springBoot,springBoot集成 ...