哈夫曼编码原理:设256种颜色在图片中各出现了a1、a2、…、an次,于是可以得到一个对应的权重数组。将权重数组以以下范例形式建立哈夫曼树。
范例:假设一个含有6个数值的权重数组9、8、3、6、7、1:
1. 首先选出两个最小的权值1、3。建立一颗二叉树:(注意小数在左)

2. 将1、3合并为4,加入原权重数组,即此时权重数组为:9、8、6、7、4
3. 再选出两个最小权值4、6,此时二叉树为:

4.依照上述方法,直到最后建立一颗哈夫曼树:(即每次从权重集合找出两个最小的数值,合并后再加入权重数组。并且同时建立二叉树,直到权重数组只剩下所有数值之和。)

建立颜色数组的哈夫曼树之后,从根节点进行遍历,做字数编码加0,右子树编码加1。(例如范例中7的哈夫曼编码为000,1的哈夫曼编码为1100)此处为变长编码。遍历整棵哈夫曼树之后即可得到256种颜色的哈夫曼编码。读取256灰度的bmp图片对映即可进行压缩。
代码部分:
类中构造器的参数为bmp解码部分,因与本讲述无关故不上传

Compression.h

#pragma once
#include "BMPbase.h"
#include <iostream>
using namespace std;
struct HuffmanTree {
HuffmanTree* parent;//parent节点
HuffmanTree* LTree;//左节点,即为1节点 应为变短编码
HuffmanTree* RTree;//右节点,即为0节点 遵循左清右重原则
int TreeIndex;//树的下标
bool isSorted;//判断是否被选取
int weight;//本节点的权值
int index;//本节点的原编码数位
};
class Compression
{
public:
Compression(BMPbase* pic, int size);
~Compression();
void BuildHuffmanTree(int min1,int min2);
void showTree(HuffmanTree * root, string str);
string* getHuffmanCode();
void choseMin(int & min);
private:
int* weightArray;
int size;//图色数
HuffmanTree** TreeArray;
int SortPoint;//排序静态指针
//int unUsed;//未被用到的颜色数
string* huffmanCode;//生成的哈夫曼编码
HuffmanTree* root;//根节点
};

Compression.cpp

#include "stdafx.h"
#include "Compression.h"

Compression::Compression(BMPbase* pic, int size)
{
this->size = size;
weightArray = new int[size];
huffmanCode = new string[size];
for (int i = 0; i < size; i++)
{
weightArray[i] = 0;
}
for (int i = 0; i < pic->pixNum; i++)//计算权值数组
{
weightArray[pic->getPicPix()[i]] += 1;//将第i个像素的颜色的权值加一
}

TreeArray = new HuffmanTree*[12000];
SortPoint = 0;
for (int i = 0; i < size; i++)//初始化树指针数组
{
if (weightArray[i] == 0)
{
huffmanCode[i] = "-1";
}
else {
TreeArray[SortPoint] = new HuffmanTree();
TreeArray[SortPoint]->index = i;
TreeArray[SortPoint]->TreeIndex = SortPoint;
TreeArray[SortPoint]->weight = weightArray[i];
TreeArray[SortPoint]->isSorted = false;
SortPoint++;
}
}

int min1, min2;
int sort = SortPoint - 1;
for (int i = 0; i < sort; i++)
{
choseMin(min1);//min1为小数 min2为大数
choseMin(min2);//min1为小数 min2为大数
BuildHuffmanTree(min1, min2);
}
int AllTreeNum = SortPoint;
string tmp1;
showTree(root, tmp1);

ofstream haffmanOut("huffman.code");
haffmanOut << AllTreeNum << endl;
for (int i = 0; i < SortPoint; i++) {
if (TreeArray[i]->LTree && TreeArray[i]->RTree){
haffmanOut <<TreeArray[i]->index << " " << TreeArray[i]->LTree->TreeIndex << " " << TreeArray[i]->RTree->TreeIndex << endl;
}
else {
haffmanOut << TreeArray[i]->index << -1 << " " << -1 << endl;
}
}

}

Compression::~Compression()
{
delete[] TreeArray;
}

void Compression::BuildHuffmanTree(int min1,int min2)//min1为小数 min2为大数
{
HuffmanTree* node = new HuffmanTree();
this->root = node;
node->index = -1;
node->LTree = TreeArray[min1];//权值小在左边
TreeArray[min1]->parent = node;
node->RTree = TreeArray[min2];//权值大在右边
TreeArray[min2]->parent = node;
node->weight = TreeArray[min1]->weight + TreeArray[min2]->weight;
node->isSorted = false;
node->TreeIndex = SortPoint;
TreeArray[SortPoint] = node;
SortPoint++;
}

void Compression::showTree(HuffmanTree* root, string str) {
//如果有左孩子就加个0,有右孩子就加个1,直到遍历完成为止
if (root->LTree != NULL)
{
showTree(root->LTree, str + '0');//如果左孩子不为空,就给编码加个0
}
if (root->RTree != NULL)
{
showTree(root->RTree, str + '1');//如果右孩子不为空,就给编码加个1
}
if(root->LTree == NULL && root->RTree == NULL) {
huffmanCode[root->index] = str;
return;
}
return;
}

string* Compression::getHuffmanCode()
{
return huffmanCode;
}

void Compression::choseMin(int &min)
{

int minA;
int i = 0;
bool flag = false;
while(i < SortPoint && !flag) {
if (!TreeArray[i]->isSorted) {
minA = i;
flag = true;
}
i++;
}
for (i = minA + 1; i < SortPoint; i++) {
if (!TreeArray[i]->isSorted) {
if (TreeArray[i]->weight < TreeArray[minA]->weight) {
minA = i;
}
}
}
TreeArray[minA]->isSorted = true;
min = minA;

}

嗯 想了想还是把bmp解码部分放出来好了,保持一下代码的完整性,代码中的注释部分是因为部分256色bmp图片不是太过严格
BMPbase.h

#pragma once
#include <fstream>
#include <iostream>
#include <iomanip>
using namespace std;
struct BitmapFileHeader {
WORD bmpHeader;//文件头“BM”
DWORD fileSize;//文件大小,字节为单位
WORD reservedWord1;//文件保留字1 必为0
WORD reservedWord2;//文件保留字2 必为0
DWORD offSet;//位图数据起始位置
};
struct BitmapFileInfo {
DWORD bmpInfoSize;//即本结构所占的大小 为28 即4字节
LONG bmpWidth;//位图的宽度
LONG bmpHeight;//位图的高度
WORD bmpPlanes;//目标设备的级别(必须为1)
WORD bmpBitCount;//每个像素的尾数,必须为1(双色)4(16色) 8(256色) 24(真彩)
DWORD bmpCompression;//必为0(BI_RGB未压缩) 1(BI_RLEB) 2(BI_RLE4)
DWORD bmpSizeImage;//位图的大小 单位为字节
LONG bmpXpelsPerMeter;//水平分辨率 每米像素数
LONG bmpYpelsPerMeter;//垂直分辨率
DWORD bmpColorUsed;//位图显示所需颜色数
DWORD bmpColorImportant;//重要的颜色数 若为0 则都重要
};
class BMPbase
{
public:

BMPbase(const char* fileName);
~BMPbase();
private:
bool fileSuccess;//判断文件是否打开成功的标志
bool fileCompression;//判断文件是否被压缩
bool bmpFileflag;//判断是否为BMP文件
bool bmpBitRight;//判断文件位数是否正确
BitmapFileHeader bmpHeader;//bmp文件头
BitmapFileInfo BmpPic;//bmp文件基本信息
BYTE* picPix;//图片数据数组

public:
bool isReadFileSuccess();
bool isBmpFile();
BitmapFileHeader getBmpHedader();//获取文件头
BitmapFileInfo getBmpInfo();//获取信息结构体
bool isBmpBitRight();//获取位图是否正确
bool isFileCompression();//获取文件是否被压缩
BYTE* getPicPix();//获取颜色数组
int pixNum;
};

BMPbase.cpp
#include "stdafx.h"
#include "BMPbase.h"

BMPbase::BMPbase(const char* fileName)
{
fileSuccess = true;//初始化文件为成功打开
bmpFileflag = true;//初始化文件为BMP文件
bmpBitRight = true;//初始化文件位数为正确
fileCompression = true;//初始化文件为未压缩
ifstream picReader(fileName, ios::binary);
if (!picReader)
{
fileSuccess = false;//文件读取失败
}
else
{
picReader.read((char*)&bmpHeader.bmpHeader, sizeof(WORD));
if (bmpHeader.bmpHeader != 0x4D42)
{
bmpFileflag = false;//文件读取失败,类型不一致
}
else//开始读取文件信息
{
picReader.read((char*)&bmpHeader.fileSize, sizeof(DWORD));//读文件大小
picReader.read((char*)&bmpHeader.reservedWord1, sizeof(WORD));//读取保留字
picReader.read((char*)&bmpHeader.reservedWord2, sizeof(WORD));//读取保留字
/*if (bmpHeader.reservedWord1 != 0x00 || bmpHeader.reservedWord2 != 0x00)//判断文件保留字是否正确
{
fileSuccess = false;//文件读取失败
}*/
picReader.read((char*)&bmpHeader.offSet, sizeof(DWORD));//读取偏移量
picReader.read((char*)&BmpPic.bmpInfoSize, sizeof(DWORD));
/*if (BmpPic.bmpInfoSize != 0x28)//判断文件信息长度是否正确
{
fileSuccess = false;//文件读取失败
}*/
picReader.read((char*)&BmpPic.bmpWidth, sizeof(DWORD));//获取宽度
picReader.read((char*)&BmpPic.bmpHeight, sizeof(DWORD));//获取高度
picReader.read((char*)&BmpPic.bmpPlanes, sizeof(WORD));//获取目标设备的级别 必须为1
/*if (BmpPic.bmpPlanes != 0x01)//判断设备级别是否正确
{
fileSuccess = false;//文件读取失败
}*/
picReader.read((char*)&BmpPic.bmpBitCount, sizeof(WORD));//获取每像素所需位数 8位图
if (BmpPic.bmpBitCount != 8)//判断是否为8位图
{
bmpBitRight = false;//文件读取失败,非8位图
}
picReader.read((char*)&BmpPic.bmpCompression, sizeof(DWORD));//获取文件压缩
if (BmpPic.bmpCompression != 0x00)//判断是否压缩
{
fileCompression = false;//文件读取失败,已被压缩
}
picReader.read((char*)&BmpPic.bmpSizeImage, sizeof(DWORD));//获取sizeImage
picReader.read((char*)&BmpPic.bmpXpelsPerMeter, sizeof(DWORD));//获取文件水平分辨率
picReader.read((char*)&BmpPic.bmpYpelsPerMeter, sizeof(DWORD));//获取文件水平分辨率
picReader.read((char*)&BmpPic.bmpColorUsed, sizeof(DWORD));//获取文件用到颜色
picReader.read((char*)&BmpPic.bmpColorImportant, sizeof(DWORD));//获取文件重要颜色
picReader.seekg(bmpHeader.offSet, ios::beg);//从文件开头开始偏移前面读出的偏移量
pixNum = BmpPic.bmpHeight*BmpPic.bmpWidth;
picPix = new BYTE[pixNum];
for (int x = 0; x < pixNum; x++)
{
picReader.read((char*)&picPix[x], sizeof(BYTE));//获取文件数据部分
}

}
}
}

BMPbase::~BMPbase()
{
for (int x = 0; x < BmpPic.bmpWidth; x++)
{
delete[] picPix;
}
}

bool BMPbase::isReadFileSuccess()
{
return fileSuccess;
}

bool BMPbase::isBmpFile()
{
return bmpFileflag;
}

BitmapFileHeader BMPbase::getBmpHedader()
{
return bmpHeader;
}

BitmapFileInfo BMPbase::getBmpInfo()
{
return BmpPic;
}

bool BMPbase::isBmpBitRight()
{
return bmpBitRight;
}

bool BMPbase::isFileCompression()
{
return fileCompression;
}

BYTE* BMPbase::getPicPix()
{
return picPix;
}

256色灰度图哈夫曼编码压缩相关推荐

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

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

  2. 对文件进行哈夫曼编码压缩与译码的C++实现 以及压缩率计算 ——HIT杨朔

    哈夫曼编码压缩原理:由于每个字符在内存中都是以ASCII码进行存储,所以每个字符都占用了八个01位,利用哈夫曼树对每个字符进行01编码,根据字符在文章中出现的频率调整01串长度,出现频率高的字符在哈夫 ...

  3. C语言哈夫曼编码压缩解压

    C语言哈夫曼编码压缩解压 一.实验目的 掌握哈夫曼编码基本运算以及存储结构表示. 二.实验内容: 1.系统要求包含以下功能 1)初始化:从终端读入字符集大小n,以及n个字符和n个权值(或者读入字符集和 ...

  4. 哈夫曼编码压缩解压缩实现不同类型文件压缩比的测试

    压缩原理及步骤&&压缩比的计算 压缩原理及步骤 压缩的第一步: 将一个文件以各个字符出现的次数为权值建立哈夫曼树,这样每个字符可以用从树根到该字符所在到叶子节点的路径来表示.(左为0, ...

  5. 利用哈夫曼编码压缩文本

    文章目录 使用哈夫曼编码进行压缩文本 文本内容 读取文件内容至内存中 遍历文本内容,获取每个字符对应出现概率值 建立哈夫曼树 获取哈夫曼编码 将转换后的编码写入新文件 检测压缩率 利用编码文件进行还原 ...

  6. 【数据结构和算法笔记】哈夫曼树的概念,构造和应用(利用哈夫曼编码压缩文本)

    目录 哈夫曼树定义: 构造哈夫曼树: 哈夫曼编码 前缀编码: 应用(压缩文本) 哈夫曼树定义: 构造哈夫曼树: 哈夫曼编码 前缀编码:  哈夫曼编码是前缀编码 哈夫曼树的性质 哈夫曼树的任意非叶结点的 ...

  7. Python实现英文文本的霍夫曼编码压缩

    霍夫曼编码作为变长码,在已知字符出现的频率的前提下,将频率高的字符用短码表示,频率低的字符用长码表示,实现用最短的码符号完整的表示出一段文本的信息. 例如 对于 这样一文本,进行字符频率统计,部分结果 ...

  8. 创建霍夫曼树,霍夫曼编码以及使用霍夫曼编码压缩文件

    那么,什么是霍夫曼树(赫夫曼树)呢? 给定n个权值(权值就是每个节点里面存放的数据,但是根据业务需求不同,存放的数据类型有些差别)作为n个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样 ...

  9. 二叉树的基本操作及哈夫曼编码/译码系统的实现

    二叉树的基本操作及哈夫曼编码/译码系统的实现 实验目的和要求 掌握二叉树的二叉链表存储表示及遍历操作实现方法. 实现二叉树遍历运算的应用:求二叉树中叶结点个数.结点总数.二叉树的高度,交换二叉树的左右 ...

最新文章

  1. 32个笔画顺序表图片_32个笔画掌握透了,练字真的不难
  2. 选择域名需注意什么才更有利于网站优化?
  3. eureka自我保护时间_SpringCloud Eureka自我保护机制
  4. 人类如何感受到四维空间?
  5. python3 selenium ie 拒绝连接报错_Python3+selenium配置常见报错解决方案
  6. redhat升级linux内核,用rpm方式升级RHEL6.1内核
  7. 北京邮电计算机课程表,北邮通信工程本科专业课程表
  8. 解决Tomcat中文乱码问题——windows平台
  9. kodi在电视上播放视频卡顿的解决办法
  10. java实现光盘摆渡_一种光盘摆渡机的制作方法
  11. 三维绕任意轴旋转矩阵
  12. 手机移动端视频全屏播放(兼容Android与iOS)
  13. SRM 543 Div2
  14. css布局之版权信息
  15. 刘銮雄-公道不在人心,是非只在时势
  16. Excel插件获取单元格批注以及设置批注
  17. 除了四大传统OA软件商,国内还有这些优秀的OA协同产品
  18. Thinkphp 6 使用RSA非对称加密算法 对接口加密解密
  19. SDCC讲师预热专访:淘宝岑文初谈开放平台架构
  20. 进销存管理系统哪个比较好?

热门文章

  1. VISTA/win7添加网络中xp系统共享打印机错误的解决方法
  2. 关于supesite后台添加外部链接后字符转义的问题
  3. 实时疫情数据+echarts地图+自定义背景
  4. 【Postman知识分享】Postman测试下载文件和上传文件(图文详解)
  5. OO——第三单元JML规格编程总结
  6. 找水果店要怎么选地址,水果店的地址选择
  7. 在Ubuntu上装CLPACK,并跑出ELSDc的代码
  8. 塑造战略的五种力量——迈克尔.波特再论“五力模型”
  9. “成功学大师”杨涛鸣被抓
  10. CiteSeer统计的计算机领域的期刊和会议的影响因子(2005)