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

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

课题:哈夫曼编码与解码 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. C# 实现系统关机、注销、重启、休眠、挂起

    原文:C# 实现系统关机.注销.重启.休眠.挂起 核心代码如下: using System; using System.Text; using System.Diagnostics; using Sy ...

  2. WPF应用程序如何重启当前的Application

    // Restart current process Method 1 System.Windows.Forms.Application.Restart(); Application.Current. ...

  3. 使用scratchbox2建立交叉编译环境

    使用scratchbox2建立交叉编译环境,使交叉编译不再烦人..... os:ubuntu 12.04.4 x64 1. 安装相关工具sudo apt-get install debootstrap ...

  4. MIPS虚拟机代码

    http://download.eeworld.com.cn/download/mamselc/472333http://download.eeworld.com.cn/detail/lamas/36 ...

  5. IDHTTP-HTTPS通讯方法(Indy10.2.3之前仅支持OpenSSL的0.9.8以前的版本)

    加载https的站点页面内容的时候记得在窗体上加上“IdSSLIOHandlerSocketOpenSSL1” 以及idhttp里面IOHandler为“IdSSLIOHandlerSocketOpe ...

  6. 【备忘】C#语言基础-1

    C#基础 注意区别哟! C#是一种托管语言,与C++不同,不能直接操作系统底层,依赖于 framework. 如果局部变量和全局变量同名,全局变量就会被屏蔽. 函数的返回值类型不是签名的一部分,所以不 ...

  7. 给 Web 开发人员推荐的通用独立 UI 组件(二)

    现代 Web 开发在将体验和功能做到极致的同时,对于美观的追求也越来越高.在推荐完图形库之后,再来推荐一些精品的独立 UI 组件.这些组件可组合在一起,形成美观而交互强大的 Web UI . 给 We ...

  8. Access Violation分成两大类:运行期和设计期(很全的解释)

    用Delphi开发程序时,我们可以把遇到的Access Violation分成两大类:运行期和设计期. 一.设计期的Access Violation 1.硬件原因  在启动或关闭Delphi IDE以 ...

  9. 数组Array

    数组Array是最基本的数据结构,在内存中为一段定长连续内存,很多编程语言都有实现. 一.一维数组 下面代码实现了一维数组和它的遍历. clear并非清空数组,而是采用具体值对数组进行初始化. imp ...

  10. 不一样的go语言-玩转语法之二

      本文继续玩转语法,是为之二.   I/O(Input/Output),输入输出是计算机最为突出的特点,也可以说是计算机最为核心的功能.没有I/O,计算机就是一堆废铜废铁.从最低层的电子元器件开始, ...