说明:这是武汉理工大学计算机学院数据结构与算法综合实验课程的第一次项目:二叉树与赫夫曼图片压缩实践代码。
源码下载地址:点击此处下载本次实验项目(运行环境:VS2017)
关注微信公众号【知行校园汇】可免费下载全部源码。
纸上得来终觉浅,绝知此事要躬行。
阶段 |
工作内容 |
交付物 |
参考资料 |
实验一 |
二叉树与赫夫曼图片压缩 |
上机实验代码 |
《数据结构和C++编程》第5章 树和二叉树 |
1、创建工程。
2、读取源文件。
3、生成哈夫曼树。
4、生成哈夫曼编码。
5、压缩原文件。
6、保存压缩文件。
7、扩展功能。
点击此处下载本次实验项目(运行环境:VS2017)
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);
int CreateHuffmanTree2(HuffmanTree &pHT, int w[], int n);
//生成Huffman编码
int HuffmanCoding(HuffmanCode &pHC, HuffmanTree &pHT);
int Select(HuffmanTree pHT, int nSize);
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 源文件代码:
#include "Huffman.h"
#include
#include
#define OK 1
#define ERROR 0
using 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;
}
// cout << "测试初始化Huffman树后的列表" << endl;
// if (TestHufTree(pHT))
// cout << "测试完毕!" << endl;
for (i = n + 1; i <= m; i++)
{
//从pHT[1...i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2
Select(pHT, i - 1, s1, s2);
pHT[s1].parent = i;
pHT[s2].parent = i; //修改s1和s2结点的父指针parent
pHT[i].lchild = s1;
pHT[i].rchild = s2; //修改i结点的左右孩子指针
pHT[i].weight = pHT[s1].weight + pHT[s2].weight; //修改权值
// cout << "257以及以后 修改权值后的值:" << i << "\t" << pHT[i].weight << endl;
}
// cout << "测试生成Huffman树后的列表" << endl;
// if (TestHufTree(pHT))
// cout << "测试完毕!" << endl;
return OK;
}
int CreateHuffmanTree2(HuffmanTree &pHT, int w[], int n)
{//w存放n个结点的权值,将构造一棵哈夫曼树pHT
int i, m;
int s1, s2;
// HuffmanTree p;
if (n <= 1) return ERROR;
m = 2 * n - 1; //n个叶子结点的哈夫曼树,有2*n-1个结点
pHT = (HuffmanTree)malloc((m +1 ) * sizeof(HTNode)); //开辟2*n各结点空间,0号单元未用
for ( i = 1; i <= n; ++i) //进行初始化
{
pHT[i].weight = w[i];
pHT[i].parent = 0;
pHT[i].lchild = 0;
pHT[i].rchild = 0;
}
for (; i <= m; ++i)
{
pHT[i].weight = 0;
pHT[i].parent = 0;
pHT[i].lchild = 0;
pHT[i].rchild = 0;
}
for (i = n + 1; i <= m; ++i) //建哈夫曼树
{
//从pHT[1...i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2
Select(pHT, i - 1, s1, s2);
pHT[s1].parent = i;
pHT[s2].parent = i; //修改s1和s2结点的父指针parent
pHT[i].lchild = s1;
pHT[i].rchild = s2; //修改i结点的左右孩子指针
pHT[i].weight = pHT[s1].weight + pHT[s2].weight; //修改权值
}
return OK;
}
//查找Huffman树节点数组中权值最小的节点
int Select(HuffmanTree pHT, int nSize) {
int minValue = 0x7FFFFFFF; //最小值
int min = 0; //元素序号
//找到最小权值的元素序号
for (int i = 1; i <= nSize; i++)
{
if (pHT[i].parent == 0 && pHT[i].weight
Compress.h 头文件代码:
#ifndef COMPRESS_H
#define COMPRESS_H
//typedef char **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 *, char**, char *, const int);
//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);
//测试相关
int TestWeight(int weight[]);
#endif
Compress.cpp 源文件代码:
#include
#include
#include "Compress.h"
#include"Huffman.h"
using namespace std;
#define OK 1
#define ERROR 0
const 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种字节出现的次数
//if (TestWeight(weight))
// cout << "测试完毕!!!" << endl << endl;
cout << "文件读取完毕!\n" << endl<= 8)
{
pBuffer[pos++] = Str2byte(cd);
for (int i = 0; i 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;
}
int TestWeight(int weight[]) {
cout << "显示256种字节出现的次数:" << endl;
cout << "Byte\t" << "Weight\t" << endl;
for (int i = 0; i < 256; i++) {
printf("0x%02X\t%d\n",i, weight[i]);
//cout << i << "\t" << weight[i] << endl;
}
return OK;
}
Main.cpp 主函数代码:
// Main.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
#include "Compress.h"
#include"Huffman.h"
using namespace std;
int main()
{
cout << "=========Huffman文件压缩=======" << endl;
cout << "请输入文件名:";
char filename[256];
cin >> filename;
if (Compress(filename) == 1) {
cout << "\n压缩完成!" << endl;
}
else {
cout << "\n压缩失败" << endl;
}
return 0;
}
后续补充