Qt实现哈夫曼编码解压缩软件详解


诸位既然点开了本帖,相信对此问题已有初步了解,哈夫曼树的原理不再赘述,我们开门见山,直入主题。

一、概要设计

问题拆解:设计一个基于哈夫曼编码的解压缩软件,这个问题我认为可以分解为以下几个子问题:

  • 读取传入文件,进行字符权重统计
  • 将出现的字符放入哈夫曼树结点,构建哈夫曼树,获取哈夫曼编码
  • 将编码相关信息写入压缩后的文件,再将传入文件的每个字符按照哈夫曼编码转换,每8个二进制位作为一个字节传入压缩后的文件
  • 解压部分:将传入的已压缩文件进行文件流读取,获取编码信息进行还原

根据这几个子问题的思路顺序,我们逐个击破,寻找解决方案:

  • 读取传入文件,需要用到文件流。这里推荐使用Qt自带的QFile文件流配以QDatastram辅助。因为,C++的文件流fstream无法识别中文路径(一说起这个,就想起Debug时的辛酸)。权重统计我用的是map记录:map<unsigned char ,int>Weightmap
  • 哈夫曼结点的构造,和二叉树没有什么区别,只是在封装的struct里面加了unsigned char 型的字符,int型的权重,string型的哈夫曼编码,和是否是叶子结点的bool型标记(哈夫曼树叶子结点才是我们需要的编码)。将前面我们获取到的字符和权重加进去。
    我们将建立好的结点放入到一个vector内(理论上什么容器都可以),进入循环:根据哈夫曼结点的权重比较进行排序(直接调用sort),每次将连个最小的结点权重取出,相加得到权重和,以权重和建立一个新的结点,新结点的左右孩子结点就是这两个结点,将新结点加入到vector中,那两个结点删除。循环结束条件为vector内只剩下一个结点。这个结点便是哈夫曼树的根结点,保存一根结点足矣。
    我们从根结点出发遍历,左子树的string+“0”,右子树的string+“1”。并将unsigned char型的字符与这个stringmap<unsigned char,string> PasswordMap 记录。
  • 传入辅助信息阶段:我们传入的信息有,PasswordMap.size(),循环传入PasswordMap->first(字符),PasswordMap->second.size()(记录编码长度),PasswordMap->second(这个字符串有可能超过8位,每个字节不足8位的部分补0)直到完全传入。另外一个方法是将所有字符与字符权重传入,在解压缩时再次构建哈夫曼树,两种思路我觉得都可以。这里我采用的第一种方法。
    传入哈夫曼编码阶段:遍历先前在读取文件时获取的字符串,将字符串的每一位转化为哈夫曼编码,用另一个字符串储存。这里不妨称这个字符串为二进制字符串,这个二进制字符串按8分割到最后可能会有不足8位的部分,对其进行补0操作。 最后再传入一个字节,记录补0数。
  • 解压部分:对应上部分的操作进行对应读取,主要思路是将压缩时传入的辅助信息提取,建立一个新的Map映射,根据这个映射,将原文件还原。

二:设计效果展示:

压缩前:
在这里插入图片描述
压缩中:
在这里插入图片描述
压缩后:
在这里插入图片描述
解压中:
在这里插入图片描述
解压后:
在这里插入图片描述

三、源代码

前面分析得很清晰,不过写代码的过程异常艰辛,充满了Debug时的汗水和泪水。
完整代码与封装好的可执行文件下载链接:https://gitee.com/sherlocknovitch/Qt_Compression
(可执行文件有58M,是因为封装了Qt的核心控件,去掉这些估计只有几百Kb的大小)
上代码:

1°MainWindow.h

先从窗口头文件看起,这块没有什么实质性的内容,只有几个槽函数(3个按钮的Click槽函数加一个让QprogressBar动起来的槽函数和一个出现文件打开错误情况时让QLineEdit清空的槽函数)
私有成员中QStirng path的作用是读取文件路径,作为压缩函数和解压缩函数的参数。
Compression* com是一个类指针,这个类是压缩类,在后面会提及。

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include"compression.h"
#include<QFileDialog>
#include<QMenu>
#include<QAction>


namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    void clear();
private slots:
    void on_pushButton_open_cli
  • 123
    点赞
  • 191
    收藏
    觉得还不错? 一键收藏
  • 30
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值