Huffman编码压缩文件

article/2025/9/29 0:55:32

文章目录

  • 前言
  • 一、Huffman编码是什么?
  • 二、Huffman编码的实现方法
  • 三、Huffman压缩文件
    • 1.统计文件个字符出现的次数
    • 2.生成Huffman树
    • 3.生成码表
    • 4.对文件进行压缩
  • 四、Huffman解压文件
  • 五、实验结果
  • 总结


前言

这个实验是我在学习信息论与编码时所做的课程实验,是用来学习Huffman编码的。整个项目是使用c++在VS2022下编写完成的。工程文件我已经发送我的仓库中,有需要的小伙伴可以通过文章最下面的链接自取。


一、Huffman编码是什么?

Huffman编码是一种无失真的信源编码方式。它通过根据字符出现的概率来分配长码与短码,从而达到降低平均码长的目的,实现压缩效果。

二、Huffman编码的实现方法

Huffman编码的具体实现方法是采用自底向上构造二叉树的方法,就是对所有信源符号按概率从高到低进行排序,每次合并概率最低的两个符号的概率,作为一个新的符号的概率,然后对所有的符号概率再重新排序合并概率最低的两个符号,这一过程一直持续,直到最后概率合并为1.

三、Huffman压缩文件

压缩文件由Encoder类进行实现,Encoder类的定义如下:

#pragma once
#ifndef ENCODER_H
#define ENCODER_H#include"huffmantree.h"
#include<vector>
#include<fstream>
#include<iostream>
#include <algorithm>
using namespace std;class Encoder 
{
private :const int size = 256;vector<int> counter;ifstream input;ofstream output;vector<HuffmanTree*> leaf;vector<vector<unsigned char>> p; // 码表HuffmanTree* tree_head;int file_size;bool openFile(string source_file, string target_file);void statistics();// 统计各个字符出现次数,并进行排序void createTree();// 生成huffman树void destroyTree(HuffmanTree* root);void creatTable(HuffmanTree* node, vector<char> temp, int len);public:Encoder();void compress(string source_file, string target_file); // 压缩编码~Encoder();};#endif

HuffmanTree的定义如下

#pragma once
#ifndef HUFFMANTREE_H
#define HUFFMANTREE_Hstruct  HuffmanTree
{HuffmanTree* lchild;HuffmanTree* rchild;int weight;  //出现次数unsigned char data;unsigned char code;  // 左1右0
};#endif

下面我将重点说明一下statistics()、createTree()、creatTable()、和 compress()

1.统计文件个字符出现的次数

void Encoder::statistics()
{unsigned char buff;while (input >> noskipws >> buff){counter.at(buff)++;file_size++;}cout << "the size of file is " << file_size << " byte"<<endl;input.clear();input.seekg(0, ios::beg);	//将文件指针指向开头
}

这里的文件需要用二进制打开,否则在Windows下会出现文档中0X1A被认作为EOF的情况,使得读取文件异常终止。

2.生成Huffman树

代码如下:

void Encoder::createTree()
{	for (int i = 0; i < size; ++i){leaf.at(i) = new HuffmanTree;leaf.at(i)->weight = counter.at(i);leaf.at(i)->code = i;leaf.at(i)->data = i;leaf.at(i)->lchild = NULL;leaf.at(i)->rchild = NULL;} //初始化HuffmanTree* lnode;HuffmanTree* rnode;HuffmanTree *f;//f = new HuffmanTree[size];while (leaf.size() > 1){f = new HuffmanTree;//从大到小排序,每次取最后两个sort(leaf.begin(), leaf.end(), [=](HuffmanTree* i1, HuffmanTree* i2) {return i1->weight > i2->weight;}); lnode = leaf.back();leaf.pop_back();rnode = leaf.back();leaf.pop_back();f->lchild = lnode;lnode->code = 1; //左1右0f->rchild = rnode;rnode->code = 0;f->weight = rnode->weight + lnode->weight;f->code = 0;leaf.push_back(f);if (leaf.size() == 1){tree_head = f;leaf.pop_back();return;}f++;}return ;
}

对所有信源符号按概率从高到低进行排序,每次合并概率最低的两个符号的概率,作为一个新的符号的概率,然后对所有的符号概率再重新排序合并概率最低的两个符号

3.生成码表

void Encoder::creatTable(HuffmanTree* node, vector<char> temp, int len)
{   if (node != NULL){if (node->lchild == NULL && node->rchild == NULL)  {temp.at(len) = node->code;p.at(node->data).assign(temp.begin()+1, temp.begin()+len+1);//用来存放码表}else{temp.at(len++) = node->code;creatTable(node->lchild, temp, len);creatTable(node->rchild, temp, len);}}
}

利用递归遍历二叉树来生成码表

4.对文件进行压缩

void Encoder::compress(string source_file, string target_file)
{vector<char> temp(size, 0);unsigned char buff;  //存放读入的字符unsigned char out = 0; //输出的字符vector<char> code;  //存放字符的编码openFile(source_file, target_file); //打开输入输出文件,必须要用二进制打开statistics(); //统计各个字符出现次数createTree();//生成Huffman树creatTable(tree_head, temp, 0);//构造码表for (vector<int>::iterator it = counter.begin(); it != counter.end(); ++it){output << *it << endl;}//写入每个字符出现的次数,解压时根据这个构建Huffman树while (input >> noskipws >> buff){code.insert(code.end(), p[buff].begin(), p[buff].end());while (code.size() >= 8) //当编码中0和1位数超过8时,将他们转化成一个字符输出{out = 0;for (int j = 0; j < 8; ++j){out = out ^ (code.at(j) << j);}output << out;vector<char>::const_iterator First = code.begin() + 8; vector<char>::const_iterator Second = code.end();code.assign(First, Second);  //将输出的编码删除}}if (code.size() != 0) //多出来不足八位的编码进行补零操作{for (int j = 0; j < code.size(); ++j){out = out ^ (code.at(j) << j);}output << out;output << code.size(); //这个记录的是最后字符的长度,解压其实并没有用到这个信息,可以删除}output.close();input.close();
}

压缩时一定要将码表先写入到压缩文件中,否者无法对文件进行解压缩,同时写入字符对应的编码时,编码中的0和1是要当作位信息写入的,我这里将编码后的0和1每八个为一组当成一个字节写入到文件中去的,最后不足8位的进行补零。

四、Huffman解压文件

void Decoder::deCompress(string sourece_file,string target_file) // 解压
{HuffmanTree* p;unsigned char buff;int count = 0;int temp;openFile(sourece_file, target_file);statistics();createTree();p = root;for (vector<int>::iterator it = counter.begin(); it != counter.end(); ++it){file_size += *it;}input >> noskipws >> buff;while (input >> noskipws >> buff){for (int i = 0; i < 8; ++i){if (!(p->lchild == NULL && p->rchild == NULL)){temp = (buff & (1 << i)) ? 1 : 0;//cout << temp;if (temp == 0){p = p->rchild;}elsep = p->lchild;}else{output << p->data;p = root;count++;if (count == file_size){cout << "decompress successfully";return;}}		}}input.close();output.close();
}

解压文件的代码大部分和压缩文件时的一样,这里比较重要的代码如上所示。主要是以二进制形式读取压缩文件中的每一个字符,并且将每一个字符按位拆分为01序列。从树的根开始,0寻找右子树,1寻找左子树,直到找到一个叶子节点,说明译码成功。将指针重新指向根节点重复该过程即可完成解压。

五、实验结果

#include"decoder.h"
#include"encoder.h"
//#include"vld.h"
int main()
{Encoder en;Decoder de;string source =R"(.\img\2.bmp)"; //目标文件string temp = R"(.\output\2.bin)"; //压缩后文件string target = R"(.\output\2.bmp)"; //解压后文件en.compress(source, temp);de.deCompress(temp, target);return 1;
}

在这里插入图片描述
该程序使用二进制读取文件,理论上来说任何格式的文件都可以进行压缩。如上图,对一个80M的mp4文件进行压缩,压缩出的文件只有18M,但是整个程序的运行时间大约需要三分钟!


总结

这次实验涉及的内容十分广泛:对文件的读取、排序算法、二叉树等等。
我将整个项目放在了我的仓库中,有需要的伙伴可以自取。
Huffman编码对不同的文件压缩效率也不一样,可以更换不同的文件试一试它的压缩效率。
https://github.com/logic8126/huffman-coding


http://chatgpt.dhexx.cn/article/hoDOlQJT.shtml

相关文章

自适应Huffman编码

自适应Huffman编码&#xff0c;可用初始编码表&#xff08;数字音视频技术&#xff0c;实验二&#xff09; 如果你已经理解了 自适应Huffman编码 &#xff0c;那么你不应该浪费时间在无聊的实验上 实验目的 1、深入掌握自适应Huffman编码的原理 2、掌握自适应Huffman编码算法…

huffman python,哈夫曼(Huffman)编码python代码实现

首先看定义 哈夫曼编码(Huffman Coding)&#xff0c;又称霍夫曼编码&#xff0c;是一种编码方式&#xff0c;哈夫曼编码是可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法&#xff0c;该方法完全依据字符出现概率来构造异字头的平均长度最短的码字&#xff0c;有时称…

Huffman Tree

Huffman Tree 哈夫曼树&#xff1b;哈夫曼编码&#xff1b;最优二叉树 自底向上 变长编码&#xff1b;前缀编码&#xff1b;熵编码 数据无损压缩&#xff1b;最短编码&#xff1b;最佳判定树 一、基本概念 Huffman Tree&#xff0c;又称最优二叉树&#xff0c;是带权路径长度最…

Huffman Codes

题目 In 1953, David A. Huffman published his paper “A Method for the Construction of Minimum-Redundancy Codes”,and hence printed his name in the history of computer science. As a professor who gives the final exam problem on Huffman codes, I am encounte…

HuffmanTree

#include "stdafx.h" #include "stdio.h" #include "stdlib.h" #include "string.h"typedef int ELEMTYPE;//哈弗曼树节点结构体 typedef struct HuffmanTree {ELEMTYPE weight;ELEMTYPE id;//区分权值相同的节点struct HuffmanTree* …

JPEG中Huffman解码实例讲解

DHT Huffuman表格式 -------------------------------------------------------------------------- 名称 字节数 值 说明 -------------------------------------------------------------------------- 段标识 1 FF 段类型 1 C4 段…

哈夫曼树(huffman)

学完了huffman树&#xff0c;讲一下自己对它的理解 huffman树遵循二叉树的原则&#xff0c;每个节点最多有两个子节点&#xff0c;但是每个节点都带有一个权重&#xff0c;如果我们要将一组字符串 “ B D C A F E ” 插入huffman树&#xff0c;每个字符都会带有一个权重&#…

Huffman树和Huffman编码

文章目录 Huffman树的定义带权路径长度WPL Huffman树的构造Huffman树的特点 Huffman编码构造Huffman编码 Huffman树的定义 哈夫曼&#xff08;Huffman&#xff09;树&#xff0c;又称最优二叉树&#xff0c;是一类带权路径长度WPL最短的树。 带权路径长度WPL 要理解带权路径…

Huffman树(哈夫曼树)

哈夫曼树又称最优二叉树&#xff0c;是一种带权路径长度最短的二叉树。所谓树的带权路径长度&#xff0c;就是树中所有的叶结点的权值乘上其到根结点的路径长度&#xff08;若根结点为0层&#xff0c;叶结点到根结点的路径长度为叶结点的层数&#xff09;。树的带权路径长度记为…

虚拟机下安装BackTrack5 (BT5)教程及BT5汉化

isare邀请您访问Backtrack中文网 http://www.backtrack.org.cn/?fromuid50397 isare邀请您访问Backtrack中文网 http://www.backtrack.org.cn/?fromuserisare PS&#xff1a;back track 安装过程中有2点要注意&#xff1a;第一&#xff1a;复制到99%的时候会等大约10来分钟&a…

bt 下载工具 deluge 配置 优化 使用

目录 Ubuntu 18 配置 deluge Deluge 安卓远程客户端 Deluge 性能调优 deluge是基于libtorrentpython的跨平台bt/pt客户端&#xff0c;适合在Linux环境下使用 deluge完全开源免费&#xff0c;对IPv6支持良好&#xff0c;性能优于transmission&#xff1b;在嵌入式设备上使用d…

BT5的U盘完整安装

BT5是什么就不用多说了&#xff0c;从网上看了许多教程&#xff0c;大多是利用unetbootin工具将ISO文件直接解压到U盘上&#xff0c;这样并不能完全使用BT&#xff0c;保存好的文件&#xff0c;重启机器后就没了&#xff0c;其实就是当做光盘使用了&#xff0c;另外还有一个方法…

有哪些好用的BT下载器?

​​​​​​2022年5个好用的 BT/ 磁力链接下载工具推荐 &#xff5c;Windows 、安卓系统 | 科技雷达 A full-featured download manager

BT是如何下载的

BT协议简介 一、BT下载是怎么来的&#xff1f; 在互联网上下载文件的方式大概有这么几种&#xff1a;FTP、HTTP、BT、eMule(电驴)等&#xff0c; 浏览器会直接支持FTP和HTTP下载&#xff0c;BT和eMule下载一般需要专用的下载软件的支持。 接下来分别简单介绍一下他们的区别&…

ed2k下载

ed2k下载 在下载ed2k资源的时候&#xff0c;浏览器一般不能直接下载&#xff0c;这个时候该怎么办呢&#xff1f; 方法一&#xff1a;下载迅雷&#xff0c;直接安装 方法二&#xff1a;使用在线工具&#xff0c;将链接转化为别的形式 https://tool.lu/urlconvert/ 方法三&am…

BT是怎么下载的

BT协议简介 一、BT下载是怎么来的? 在互联网上下载文件的方式大概有这么几种:FTP、HTTP、BT、eMule(电驴)等, 浏览器会直接支持FTP和HTTP下载,BT和eMule下载一般需要专用的下载软件的支持。 接下来分别简单介绍一下他们的区别: FTP 是 File Transfer Protocol(文件…

最好用的bt下载器qbittorrent下载安装使用教程

qBittorrent绝对是我心目中BT下载工具中的NO.1&#xff0c;虽说我平时也会用迅雷下载国内的某些资源&#xff0c;但是仍然不妨碍它是我心目中的主力下载神器&#xff01;它可以说是我最早接触的除迅雷之外的一款BT下载神器。它是完全免费的种子和磁力链接下载工具&#xff0c;最…

BT5 WIFI破解

实验环境 VMwareWorkstation 9.0 BackTrack5 R3-GNOME-32 工具说明 VMware&#xff1a;著名的虚拟机软件&#xff0c;本实验采用虚拟机环境下安装BackTrack。 BackTrack&#xff1a;是一个基于Ubuntu GNU/Linux的发行版本&#xff0c;主要用做数字取证和入侵测试。其无线安全审…

BT5下载地址

http://www.backtrack-linux.org/downloads/ 下载方法&#xff1a; 1,先填写好网页里的三个框,如: Your Name(你的名字): ABC Email Address(邮箱): ABC163.com Country(国家): china 2,然后点"download" 3,按照自己的…

最全BT介绍

BitTorrent 简介 riba2534 2021年04月11日 19:26 阅读 851 关注 BitTorrent 简介 从 P2P 说起 经常在网上飙车的老司机应该都知道 BT 下载&#xff0c;但是有时候拿到了种子却下载不动&#xff0c;会不会很抓狂&#xff0c;是不是还觉得是自己网不行&#xff0c;那作为一…