使用Huffman压缩算法,对一幅BMP格式的图片文件进行压缩。图片文件名为“Pic.bmp”,压缩后保存为“Pic.bmp.huf”文件。

程序截图:

Main.cpp

#include"menu.h"int main() {show();return 0;
}

meun.h

#ifndef MENU_H
#define MENU_Hvoid show();#endif // !MENU_H

menu.cpp

#include"menu.h"
#include<iostream>
#include"Compress.h"
#include"global.h"
using namespace std;void show() {cout << "========== Huffman 文件压缩 ==========" << endl;cout << "请输入文件名:";cin >> filename;if (Compress(filename) == 1)cout << "\n压缩完成!" << endl;else cout << "\n压缩失败!" << endl;cout << endl;system("pause");
}

Huffman.h

#ifndef HUFFMAN_H
#define HUFFMAN_H//Huffman树节点
typedef struct
{int weight;    //权值int parent; //父节点int lchild;    //左孩子int rchild;    //右孩子
}HTNode, *HuffmanTree;typedef char **HuffmanCode;       //Huffman编码//生成Huffman树
int CreateHuffmanTree(HuffmanTree pHT, int weight[], int n);//生成Huffman编码
int HuffmanCoding(HuffmanCode &pHC, HuffmanTree  &pHT);void Select(HuffmanTree &HT, int i, int&s1, int&s2);int TestHufTree(HuffmanTree pHT);
void TestHufCode(int root, HuffmanTree &pHT, HuffmanCode &pHC);#endif

Huffman.cpp

#define _CRT_SECURE_NO_WARNINGS
#include"Huffman.h"
#include<iostream>
#include<malloc.h>#define OK 1
#define ERROR 0using namespace std;//生成Huffman树
int CreateHuffmanTree(HuffmanTree pHT, int weight[], int n) {int s1, s2, i;int m = 2 * n - 1;//初始化for (i = 1; i <= n; i++) {pHT[i].weight = weight[i - 1];pHT[i].lchild = 0;pHT[i].rchild = 0;pHT[i].parent = 0;}for (i = n + 1; i <= m; i++) {pHT[i].parent = 0;pHT[i].lchild = 0;pHT[i].rchild = 0;pHT[i].weight = 0;}for (i = n + 1; i <= m; i++){//从pHT[1...i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2Select(pHT, i - 1, s1, s2);pHT[s1].parent = i;pHT[s2].parent = i; //修改s1和s2结点的父指针parentpHT[i].lchild = s1;pHT[i].rchild = s2; //修改i结点的左右孩子指针pHT[i].weight = pHT[s1].weight + pHT[s2].weight; //修改权值}return OK;
}//查找Huffman树节点数组中权值最小的节点
void Select(HuffmanTree &pHT, int i, int &s1, int &s2) {int minValue = 0x7FFFFFFF;//找到最小的一个权值for (int j = 1; j <= i; j++) {if (pHT[j].parent == 0 && pHT[j].weight < minValue) {minValue = pHT[j].weight;s1 = j;}}minValue = 0x7FFFFFFF;//找到倒数第二小的权值for (int j = 1; j <= i; j++) {if (j != s1 && pHT[j].parent == 0 && pHT[j].weight < minValue) {minValue = pHT[j].weight;s2 = j;}}
}//生成Huffman编码
int HuffmanCoding(HuffmanCode &pHC, HuffmanTree &pHT)
{//无栈非递归遍历Huffman树,求Huffman编码char cd[256] = { '\0' }; //记录访问路径int cdlen = 0;             //记录当前路径长度for (int i = 1; i < 512; i++) pHT[i].weight = 0;   //遍历Huffman树时用做节点的状态标志int p = 511;         //根节点while (p != 0) {//向左if (pHT[p].weight == 0) {pHT[p].weight = 1;if (pHT[p].lchild != 0) {p = pHT[p].lchild;cd[cdlen++] = '0';}//登记叶子节点的字符的编码else if (pHT[p].rchild == 0) {pHC[p] = (char*)malloc((cdlen + 1) * sizeof(char));cd[cdlen] = '\0';strcpy(pHC[p], cd);//复制编码}}//向右else if (pHT[p].weight == 1) {pHT[p].weight = 2;//右孩子为叶子节点if (pHT[p].rchild != 0) {p = pHT[p].rchild;cd[cdlen++] = '1';}}//退回父节点,编码长度减一else {pHT[p].weight = 0;p = pHT[p].parent;cdlen--;}}return OK;
}int TestHufTree(HuffmanTree pHT) {cout << "哈夫曼树的每个节点信息为:" << endl;cout << "Byte\t\tWeight\tParent\tLchild\tRchild\n";for (int i = 1; i < 512; i++) {//判断语句为了对齐格式if (i <= 99) cout << "pHT[" << i << "]\t\t" << pHT[i].weight << "\t" << pHT[i].parent << "\t" << pHT[i].lchild << "\t" << pHT[i].rchild << endl;elsecout << "pHT[" << i << "]\t" << pHT[i].weight << "\t" << pHT[i].parent << "\t" << pHT[i].lchild << "\t" << pHT[i].rchild << endl;}return OK;
}void TestHufCode(int root, HuffmanTree &pHT, HuffmanCode &pHC) {if (root <= 1) return;if (pHT[root].lchild == 0 && pHT[root].rchild == 0)printf("0x%02X\t%s\n", root - 1, pHC[root - 1]);if (pHT[root].lchild)//访问左孩子TestHufCode(pHT[root].lchild, pHT, pHC);if (pHT[root].rchild)//访问右孩子TestHufCode(pHT[root].rchild, pHT, pHC);
}

Compress.h

#ifndef COMPRESS_H
#define COMPRESS_H#include"Huffman.h" //Encode函数生明会用到HuffmanCode//文件头
struct HEAD
{char type[4];int length;int weight[256];
};//实现文件压缩
int Compress(const char *pFilename);//读取源文件和初始化头文件的信息
int InitHead(const char * pFilname, HEAD & sHead);//利用Huffman编码 实现压缩编码
int Encode(const char *pFilname, const HuffmanCode pHC, char *pBuffer, const int nSize);//将二进制字符串转换成字节
char Str2byte(const char * pBinStr);//生成压缩文件
int WriteFile(const char * pFilename, const HEAD sHead, const char * pBuffer, const int nSize);//显示256种字节出现的次数
void showWeight(int weight[]);#endif

Compress.cpp

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <stdlib.h>
#include "Compress.h"
#include"Huffman.h"using namespace std;#define OK 1
#define ERROR 0const int SIZE = 256;//扫描文件和初始化头文件的信息
int InitHead(const char * pFilname, HEAD & sHead)
{strcpy(sHead.type, "HUF");       //文件类型sHead.length = 0;                //源文件长度for (int i = 0; i < SIZE; i++)sHead.weight[i] = 0;        //权值//以二进制流形式打开文件FILE *in = fopen(pFilname, "rb");//扫描文件,获得权重int ch;while ((ch = fgetc(in)) != EOF){sHead.weight[ch]++;sHead.length++;}//关闭文件fclose(in);in = NULL;return OK;
}//得到编码文件
int Compress(const char * pFilename)
{//打开并扫描文件cout << "正在读取文件……" << endl;int weight[256] = { 0 };  FILE* in = fopen(pFilename, "rb");int tempch;while ((tempch = getc(in)) != EOF)//获取权重weight[tempch]++;//测试,显示256种字节出现的次数//showWeight(weight);cout << "文件读取完毕!\n" << endl << endl;fclose(in);//将编码生成Huffman树int n = 256;                     //Huffman树共有n个叶子节点int m = 2 * n - 1;                   //那么就有2n+1个节点HuffmanTree pHT = new HTNode[m + 1];    //定义Huffman树CreateHuffmanTree(pHT, weight, n);//测试,输出 Huffman 树每个节点的信息//TestHufTree(pHT);//生成Huffman编码char** pHC = new char*[n + 1]; //编码for (int i = 1; i <= n; i++)pHT[i].weight = weight[i - 1];HuffmanCoding(pHC, pHT);//测试,显示字节的Huffman编码信息//cout << "\n哈夫曼树的编码信息为:" << endl;//cout << "Byte\tHuffmanCode" << endl;//TestHufCode(511, pHT, pHC);//计算编码缓冲区大小int nSize = 0;for (int i = 0; i < 256; i++)nSize += weight[i] * strlen(pHC[i + 1]);nSize = (nSize % 8) ? nSize / 8 + 1 : nSize / 8;//对编码文件进行压缩char *pBuffer = NULL;pBuffer = new char[nSize];memset(pBuffer, 0, (nSize) * sizeof(char));Encode(pFilename, pHC, pBuffer, nSize);if (!pBuffer) {return ERROR;}HEAD sHead;InitHead(pFilename, sHead);cout << "目标文件大小:" << sHead.length << "字节" << endl;int afterlen = WriteFile(pFilename, sHead, pBuffer, nSize);cout << "压缩文件大小:" << afterlen << "字节  \n其中头文件sHead大小:" << sizeof(sHead) << "字节" << endl;cout << "压缩比率:" << (double)afterlen * 100 / sHead.length << "%" << endl;delete pHT; delete[] pHC;delete pBuffer;return OK;
}//实现压缩编码
int Encode(const char * pFilname, const HuffmanCode pHC, char * pBuffer, const int nSize)
{//打开文件FILE *in = fopen(pFilname, "rb");//开辟缓冲区nipBuffer = (char *)malloc(nSize * sizeof(char));if (!pBuffer)cout << "开辟缓冲区失败" << endl;char cd[SIZE] = { 0 };        //工作区int pos = 0;              //缓冲区指针int ch;//扫描文件while ((ch = fgetc(in)) != EOF){strcat(cd, pHC[ch + 1]);//压缩编码while (strlen(cd) >= 8){pBuffer[pos++] = Str2byte(cd);for (int i = 0; i < SIZE - 8; i++){cd[i] = cd[i + 8];}}}if (strlen(cd) > 0)pBuffer[pos++] = Str2byte(cd);fclose(in);    return OK;
}//生成压缩文件
int WriteFile(const char * pFilename, const HEAD sHead, const char * pBuffer, const int nSize)
{//生成文件名char filename[256] = { 0 };strcpy(filename, pFilename);strcat(filename, ".huf");//以二进制流形式打开文件FILE * out = fopen(filename, "wb");//写文件fwrite(&sHead, sizeof(HEAD), 1, out);//写压缩后的编码fwrite(pBuffer, sizeof(char), nSize, out);//关闭文件,释放文件指针fclose(out);out = NULL;cout << "生成压缩文件:" << filename << endl;int len = sizeof(HEAD) + strlen(pFilename) + 1 + nSize;return len;
}//将字符串转换成字节
char Str2byte(const char * pBinStr)
{char b = 0x00;for (int i = 0; i < 8; i++){b = b << 1;        //左移一位if (pBinStr[i] == '1'){b = b | 0x01;}}return b;
}// 显示 256 种字节的出现的次数
void showWeight(int weight[]) {cout << "原文件每个字符的权值为:" << endl;cout << "Byte\t" << "Weight\t" << endl;for (int i = 0; i < 256; i++) printf("0x%02X\t%d\n", i, weight[i]);
}

gobal.h

#ifndef GLOBAL_H
#define GLOBAL_Hchar  filename[256];#endif // !GLOBAL_H

运行截图:

【数据结构与算法实验】二叉树与哈夫曼图片压缩相关推荐

  1. 武汉理工大学数据结构综合实验——二叉树与赫夫曼图片压缩

    文章目录 实验目的 主要仪器设备及耗材 一.实验要求 二.分析与设计 1.数据结构的设计 2.核心算法设计 生成Huffman树的算法 生成Huffman编码的算法 压缩编码的算法 3.测试用例设计 ...

  2. [数据结构与算法综合实验]二叉树与哈夫曼图片压缩

    文章目录 一.实验要求 二.效果展示 三.源码 3.1.Compress.cpp 3.2.Compress.h 3.3.global.h 3.4.Huffman.cpp 3.5.Huffman.h 3 ...

  3. 二叉树与哈夫曼图片压缩(c++)

    开发一个控制台程序,使用Huffnan压缩算法对bmp格式图片文件进行压缩 项目结构 运行结果 Huffman.h #pragma once #include<iostream> usin ...

  4. 哈夫曼图片压缩及解压

    哈夫曼图片压缩及解压 文件 功能 Huffman 哈夫曼编码 compress 解压 //Compress.h #ifndef COMPRESS_H #define COMPRESS_H typede ...

  5. 数据结构与算法之Huffman tree(赫夫曼树 / 霍夫曼树 / 哈夫曼树 / 最优二叉树)

    目录 赫夫曼树概述 定义 构造赫夫曼树步骤 代码实现 赫夫曼树概述 HuffmanTree因为翻译不同所以有其他的名字:赫夫曼树.霍夫曼树.哈夫曼树 赫夫曼树又称最优二叉树,是一种带权路径长度最短的二 ...

  6. 【数据结构Note5】- 树和二叉树(知识点超细大全-涵盖常见算法 排序二叉树 线索二叉树 平衡二叉树 哈夫曼树)

    文章目录 5.1 树和二叉树引入 5.1.1 树的概念 5.1.2 树的表示 5.1.3 树中基本术语 5.2 二叉树 5.2.1 概念 5.2.2 二叉树的性质 5.2.3 特殊的二叉树 5.2.4 ...

  7. 本科课程【数据结构与算法】实验4—— 构造哈夫曼树、深度优先搜索

    大家好,我是[1+1=王], 热爱java的计算机(人工智能)渣硕研究生在读. 如果你也对java.人工智能等技术感兴趣,欢迎关注,抱团交流进大厂!!! Good better best, never ...

  8. 数据结构与算法 3:二叉树,遍历,创建,释放,拷贝,求高度,面试,线索树

    [本文谢绝转载,原文来自http://990487026.blog.51cto.com] 树 数据结构与算法 3:二叉树,遍历,创建,释放,拷贝,求高度,面试,线索树二叉树的创建,关系建立二叉树的创建 ...

  9. 常考数据结构与算法:输出二叉树的右视图

    题目描述 请根据二叉树的前序遍历,中序遍历恢复二叉树,并打印出二叉树的右视图 上图树的右视图为:{1,4,3,7} 做此题之前可以先做下面3道题: 1. 常考数据结构与算法:求二叉树的层序遍历 2.常 ...

最新文章

  1. 详解谷歌最强NLP模型BERT(理论+实战)
  2. 实践自定义UI—RLF...(RelativeLayout LinearLayout FrameLayout....)
  3. 2015年3月-前端开发月刊
  4. Python零碎知识(7):硬性出错
  5. 电影推荐_亲和性分析_规则提取(数据挖掘入门与实践-实验6)
  6. vuex webpack 配置_vue+webpack切换环境和打包之后服务器配置
  7. 安装JDK 9与使用jshell
  8. load average多少是正常_对 cpu 与 load 的理解及线上问题处理思路解读
  9. 【POJ3461】Oulipo(字符串Hash)
  10. IE9兼容性视图与IE9标准视图
  11. arraylist 线程安全_Java集合---ArrayList的实现原理
  12. asp解决“另一个SqlParameterCollection中已包含SqlParameter”的方法
  13. 微信公众号用户标签php,C#微信开发之微信公众号标签管理功能
  14. 天善智能网络爬虫学习~
  15. openGL es2.0 粒子系统之烟花
  16. 加载property配置文件
  17. 概念辨析理解--TEX、LATEX、TEXLive和Lyx的区别和联系
  18. Huffman编码/译码问题
  19. python 导入pygame模块
  20. Cadence Allegro SPB 16.6高速下载+补丁+破解Crack教程

热门文章

  1. MXNet 分布式架构——parameter server详解
  2. 网络中什么是mce,ce,pe,p
  3. 2018年计算机专业对口升学,2018年届对口升学考试计算机专业月考三试题.doc
  4. 从功能到测开,阿里巴巴软件测试面经,看看大厂的技术栈
  5. NGS测序结果中duplicate序列问题的理解
  6. 关于计算机系的三句半,廉洁诚信三行标语与三句半文字
  7. java生成pem格式公钥_如何以.pem格式保存证书中的公钥
  8. PHP message:filesize(): stat failed for 错误
  9. 第一个Android应用 扫描宝 欲挑战传统扫描枪
  10. Nexpose漏洞扫描器