哈夫曼压缩&解压缩

  • Ⅰ 前言
  • Ⅱ 需求分析&主函数带参的应用
    • A. 需求分析
    • B. 压缩部分
    • B. 解压缩部分
  • Ⅲ 哈夫曼压缩
    • A. 代码分析
    • B. 从文件中读取内容生成频度表
    • C. 将编码写入文件
    • D. 哈夫曼压缩完整代码
    • E. 运行结果
  • Ⅳ 哈夫曼解压缩
    • A. 代码分析
    • B. 从压缩文件中读取频度表
    • C. 解码
    • D. 哈夫曼解压缩完整代码
    • E. 运行结果
  • Ⅴ 一些补充

Ⅰ 前言

在之前的文章里,我先介绍了如何构造哈夫曼树及实现哈夫曼编码,并用程序完成了这个部分。
【C语言->数据结构与算法】->树与二叉树概念&哈夫曼树的构造
【C语言->数据结构与算法】->哈夫曼压缩&解压缩->第一阶段->哈夫曼编码&解码的实现

这个程序的框架已经构架完成,可以完成最终的部分了。在第一阶段中,我们完成了对任意字符串的编码和解码,现在要做的是,如何把这个字符串变成文件的内容。

我先把第一阶段的函数部分代码放在这里。

#include <stdio.h>
#include <string.h>
#include <malloc.h>#include "tyz.h"
#include "hufmanTree.h"u8 *decoding(u8 *hufCode, u32 characterCount, HUFMAN_TREE_NODE *hufmanTreeNode) {u8 *decode = NULL;u32 i;u32 index = 0;u32 sum = 0;u32 father = 2 * characterCount - 2;for (i = 0; i < characterCount; i++) {sum += hufmanTreeNode[i].attribute.frequency;}decode = (u8 *) calloc(sizeof(u8), sum);for (i = 0; hufCode[i]; i++) {if ('0' == hufCode[i]) {decode[index++] = hufmanTreeNode[hufmanTreeNode[father].leftChild].attribute.character;father = characterCount * 2 - 2;} else {father = hufmanTreeNode[father].rightChild;if (-1 == hufmanTreeNode[father].leftChild) {decode[index++] = hufmanTreeNode[father].attribute.character;father = characterCount * 2 - 2;}}}return decode;
}void destoryCode(u8 *hufCode) {if (NULL == hufCode) {return;}free(hufCode);
}u8 *coding(u8 *str, u32 *orientate, u32 characterCount, HUFMAN_TREE_NODE *hufmanTreeNode) {u8 *code = NULL;u32 i;u32 sum = 0;for (i = 0; i < characterCount; i++) {sum += hufmanTreeNode[i].attribute.frequency * strlen(hufmanTreeNode[i].hufmanCode);}code = (u8 *) calloc(sizeof(u8), sum);for (i = 0; str[i]; i++) {strcat(code, hufmanTreeNode[orientate[str[i]]].hufmanCode);}return code;
}void creatHufmanCode(u8 *code, u32 index, u32 root, HUFMAN_TREE_NODE *hufmanTreeNode) {if (-1 == hufmanTreeNode[root].leftChild) {code[index] = 0;strcpy(hufmanTreeNode[root].hufmanCode, code);return;} else {code[index] = '0';creatHufmanCode(code, index+1, hufmanTreeNode[root].leftChild, hufmanTreeNode);code[index] = '1';creatHufmanCode(code, index+1, hufmanTreeNode[root].rightChild, hufmanTreeNode);}
}u32 searchMinimumNode(u32 count, HUFMAN_TREE_NODE *hufmanTreeNode) {u32 i;u32 minIndex = -1;for (i = 0; i < count; i++) {if (FALSE == hufmanTreeNode[i].visited && (-1 == minIndex || hufmanTreeNode[minIndex].attribute.frequency > hufmanTreeNode[i].attribute.frequency)) {minIndex = i;}}hufmanTreeNode[minIndex].visited = TRUE;return minIndex;
}void creatHufmanTree(u32 characterCount, HUFMAN_TREE_NODE *hufmanTreeNode) {u32 i;u32 leftChild;u32 rightChild;u32 count = characterCount;for (i = 0; i < count - 1; i++) {leftChild = searchMinimumNode(count+i, hufmanTreeNode);rightChild = searchMinimumNode(count+i, hufmanTreeNode);hufmanTreeNode[count+i].visited = FALSE;hufmanTreeNode[count+i].hufmanCode = NULL;hufmanTreeNode[count+i].leftChild = leftChild;hufmanTreeNode[count+i].rightChild = rightChild;hufmanTreeNode[count+i].attribute.character = '@';hufmanTreeNode[count+i].attribute.frequency = hufmanTreeNode[leftChild].attribute.frequency + hufmanTreeNode[rightChild].attribute.frequency;}
}void showHufmanTreeNode(u32 characterCount, HUFMAN_TREE_NODE *hufmanTreeNode) {u32 i;printf("字符  频度  左孩子  右孩子  编码\n");for (i = 0; i < characterCount; i++) {printf("%-5c %-5d %-7d %-7d %-10s\n", hufmanTreeNode[i].attribute.character,hufmanTreeNode[i].attribute.frequency,hufmanTreeNode[i].leftChild,hufmanTreeNode[i].rightChild,hufmanTreeNode[i].hufmanCode == NULL ? "NULL" : hufmanTreeNode[i].hufmanCode);}
}void destoryHufmanTreeNode(u32 count, HUFMAN_TREE_NODE *hufmanTreeNode) {u32 i;if (NULL == hufmanTreeNode) {return;}for (i = 0; i < count; i++) {free(hufmanTreeNode[i].hufmanCode);}free(hufmanTreeNode);
}HUFMAN_TREE_NODE *initHufmanTreeNode(u32 characterCount, u32 *orientate, ATTRIBUTE *attributeList) {u32 i;u32 nodeCount;HUFMAN_TREE_NODE *hufmanTreeNode;nodeCount = characterCount * 2 - 1;hufmanTreeNode = (HUFMAN_TREE_NODE *) calloc(sizeof(HUFMAN_TREE_NODE), nodeCount);for (i = 0; i < characterCount; i++) {hufmanTreeNode[i].visited = FALSE;hufmanTreeNode[i].hufmanCode = (u8 *) calloc(sizeof(u8), characterCount);hufmanTreeNode[i].leftChild = hufmanTreeNode[i].rightChild = -1;hufmanTreeNode[i].attribute = attributeList[i];orientate[attributeList[i].character] = i;}return hufmanTreeNode;
}void showAttributeList(u32 characterCount, ATTRIBUTE *attributeList) {u32 i;for (i = 0; i < characterCount; i++) {printf("频度:%d 符号:%c\n", attributeList[i].frequency, attributeList[i].character);}
}void destoryAttributeList(ATTRIBUTE *attributeList) {if (NULL == attributeList) {return;}free(attributeList);
}ATTRIBUTE *initAttributeList(u8 *str, u32 *ascii, u32 *characterCount) {u32 i;u32 index = 0;u32 count = 0;ATTRIBUTE *attributeList;for (i = 0; str[i]; i++) {ascii[str[i]]++;}for (i = 0; i < 256; i++) {count += (ascii[i] != 0); }*characterCount = count;attributeList = (ATTRIBUTE *) calloc(sizeof(ATTRIBUTE), count);for (i = 0; i < 256; i++) {if (ascii[i] != 0) {attributeList[index].character = (u8) i;attributeList[index++].frequency = ascii[i];}}return attributeList;
}int main() {u8 str[128];u8 code[256];u8 *hufCode = NULL;u8 *decode = NULL;u32 ascii[256] = {0};u32 orientate[256] = {0};u32 characterCount;ATTRIBUTE *attributeList = NULL;HUFMAN_TREE_NODE *hufmanTreeNode = NULL;printf("请输入字符串:\n");gets(str);attributeList = initAttributeList(str, ascii, &characterCount);showAttributeList(characterCount, attributeList);hufmanTreeNode = initHufmanTreeNode(characterCount, orientate, attributeList);creatHufmanTree(characterCount, hufmanTreeNode);creatHufmanCode(code, 0, 2*characterCount-2, hufmanTreeNode);printf("Hufman Tree Below\n");showHufmanTreeNode(2*characterCount-1, hufmanTreeNode);hufCode = coding(str, orientate, characterCount, hufmanTreeNode);printf("Hufman Code Below\n");printf("%s\n", hufCode);decode = decoding(hufCode, characterCount, hufmanTreeNode);printf("Hufman Decode Below\n");printf("%s\n", decode);destoryCode(hufCode);destoryCode(decode);destoryAttributeList(attributeList);destoryHufmanTreeNode(characterCount, hufmanTreeNode);return 0;
}

我们现在需要思考的是,在对文件进行编码压缩解压缩的过程中,和对字符串进行这个操作的过程中,哪些部分是共通的?哪些部分是需要改变的?

Ⅱ 需求分析&主函数带参的应用

A. 需求分析

在用户要压缩文件时,我们需要用户输入一个TA需要压缩的文件名,要生成的文件名可输入可不输入。
在用户要解压缩文件时,我们需要用户输入TA需要解压缩的文件,并输入要生成的文件名,因为我们不知道用户的文件到底是什么类型的,所以需要用户自己输入要生成的文件名包括扩展名,以此来生成他需要的文件类型。

根据这两个需求,我们如何让用户做到这一点呢?答案便是主函数带参

若对这个知识点有疑问的同学可以看我下面这篇文章,可以大概了解这里的内容。
【C语言->数据结构与算法】->关于主函数带参

B. 压缩部分

如果用户没有输入要生成的文件名,按照其他的压缩软件的规则,会生成一个和源文件名字相同但是扩展名相同的文件。
比如我要压缩下面这个文件

【C语言-数据结构与算法】-哈夫曼压缩解压缩-终局-如何做一个自己独有的压缩软件相关推荐

  1. 数据结构与算法 / 霍夫曼树、霍夫曼编码和解码

    一. 诞生原因 找出存放一串字符所需的最少的二进制编码. 二. 构造方法 首先统计出每种字符出现的频率,即:概率.权值. 例如:频率表 A:60,    B:45,   C:13   D:69   E ...

  2. 数据结构与算法--哈夫曼树及其应用

    一.哈夫曼树的基本概念 1) 路径: 从树中一个结点到另一个结点之间的分支构成这两个结点间的路径 2) 结点的路径长度: 两结点间路径上的分支数           3) 树的路径长度:从树根到每一个 ...

  3. 数据结构与算法——赫夫曼树基本实现

    目录 一.赫夫曼树 1.1 基本介绍 1.2 赫夫曼树创建步骤图解 1.3  代码实现 二.赫夫曼编码 2.1 基本介绍 2.1.1  通讯领域 - 定长编码 - 举例说明 2.1.2  通讯领域 - ...

  4. 数据结构与算法(赫夫曼树,赫夫曼编码)

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

  5. 数据结构与算法--哈夫曼树应用

    第1关:统计报文中各个字符出现的次数 任务描述 本关任务: 给定一串文本,统计其中各个字符出现的次数: 测试说明 平台会对你编写的代码进行测试: 测试输入:` abcdeabcdeabcdabcdab ...

  6. C语言霍夫曼编码压缩,数据结构大作业——哈夫曼编码压缩BMP格式文件

    数据结构大作业--哈夫曼编码压缩BMP格式文件 首先需要了解BMP图像格式 BMP图像格式详解 其次需要了解哈夫曼编码如何对BMP文件进行压缩 哈夫曼压缩与解压缩 编程部分 使用的头文件 虽然这里用了 ...

  7. 数据结构树-->霍夫曼树

    目录 1. 数据结构树–>树基础 2. 数据结构树–>二叉树 3. 数据结构树–>二叉查找树\二叉排序树 4. 数据结构树–>平衡二叉树 5. 数据结构树–>霍夫曼树 6 ...

  8. c语言数据结构插入算法说明,C语言数据结构插入算法

    C语言数据结构插入算法 C语言数据结构插入算法 C语言数据结构 数据结构学习 ->是二目运算符 p->a 引用了指针p指向的结构体的成员a. 整合 void unionL(List *La ...

  9. 数据结构学习记录——哈夫曼树(什么是哈夫曼树、哈夫曼树的定义、哈夫曼树的构造、哈夫曼树的特点、哈夫曼编码)

    目录 什么是哈夫曼树 哈夫曼树的定义 哈夫曼树的构造 图解操作 代码实现 代码解析 哈夫曼树的特点 哈夫曼编码 不等长编码 二叉树用于编码 哈夫曼编码实例 什么是哈夫曼树 我们先举个例子: 要将百分制 ...

最新文章

  1. PCL点云特征描述与提取(2)
  2. 知乎如何洞察你的真实喜好?首页信息流技术揭秘
  3. Lintcode363 Trapping Rain Water solution 题解
  4. python类的函数_python 类函数
  5. js学习总结----轮播图之渐隐渐现版
  6. rsync+inotify远程同步
  7. 光耦驱动单向可控硅_光耦是什麽?
  8. 从零开始编写深度学习库(二)FullyconnecteLayer CPU编写
  9. 手机应用软件测试经验总结
  10. com.fr.decision.webservice.v10.login.LoginService
  11. 14套新鲜出炉的网页图标素材下载
  12. 免费的3D GIS 软件,特点与应用领域介绍
  13. 算法-第四版-练习1.2.3解答
  14. ZDNS宣布完成B轮融资,根服务器之外,顶级域名系统迎重要机遇
  15. 微信小程序的数据库用mysql可以_微信小程序之在前端使用数据库
  16. Java | Java模拟实现扑克牌洗牌、发牌过程
  17. mac更改launchpad图标大小
  18. SDS新书的来龙去脉 amp;amp; SDS序言 - 倪光南:众筹出书也是一种创新
  19. 如何成为一名白帽子?
  20. Android 集成google map,Markers ,定位,聚合

热门文章

  1. ***Excel表的读取***
  2. 重磅 | 由浅入深的 AI 学习路线,最详细的资源整理!
  3. MINDOC文档管理系统安装
  4. ORB_SLAM2中基础矩阵F求解的原理及源码分析
  5. 做自己的操作系统光盘
  6. 面朝大海,春暖花开 一个字的差别
  7. 2010年湖南省第六届大学生程序设计大赛 F题 “Biggest Number” CSG - 1051 // UVA 11882 (dfs+bfs+剪枝)
  8. 【车载以太网】【组织】最详国际标准组织与标准介绍
  9. 机器学习介绍——个人经验
  10. msp430g2553的倒车雷达超声波测距子系统