#include "compression.h"
#include <qmath.h>
Compression::Compression()
{
}
//把二进制串转化为int型,即将压缩时每8个二进制位的字符串转化为ASCII码,传入压缩后的文件
int binarystringtoint(string binarystring)
{
int sum = 0;
for(int i=0;i<binarystring.size();i++)
{
if(binarystring[i]=='1')
{
int j = pow(2,binarystring.size()-i-1);
sum += j;
}
}
return sum;
}
//把int型转换为二进制串,解压时使用
string inttobinarystring(int value)
{
string binarystring;
while(value>0)
{
int r = value%2;
if(r==1)
binarystring.insert(0,1,'1');
else
binarystring.insert(0,1,'0');
value = value/2;
}
//不足8位,后补0
if(binarystring.size()<8)
{
binarystring.insert(0,8-binarystring.size(),'0');
}
return binarystring;
}
//哈夫曼树结点权重比较
bool compare(HuffmanTreeNode* node1, HuffmanTreeNode* node2)
{
return node1->Weight.second < node2->Weight.second;
}
//删除申请空间中哈夫曼树的函数
void Compression::Delete(HuffmanTreeNode *&root)
{
if(root==NULL)
return;
//递归调用
Delete(root->leftson);
Delete(root->rightson);
}
//权重映射的初始化
void Compression::Weightmap_Init(QFile& in)
{
QByteArray a;
while (!in.atEnd())
{
a=in.read(1024);
//一次性读取1024个字节,不足1024个字节则读取全部
string b=a.toStdString();
//转换为string
for(int i=0;i<b.size();i++)
{
unsigned char ch=b[i];
source_string += ch;
weightmap[ch]++;
}
}
}
//按照哈夫曼编码映射初始化类中的binarystring
void Compression::BinaryString_Init()
{
for(int i=0;i<source_string.size();i++)
binary_string += passwordmap[source_string[i]];
}
//建立哈夫曼结点,进行初始化操作
HuffmanTreeNode* Compression::MakehuffmanTreeNode(int i)
{
HuffmanTreeNode* huffman = new HuffmanTreeNode;
huffman->Weight.first = i;
huffman->Weight.second = weightmap[i];
huffman->tag = 0; //是叶子结点
huffman->leftson = NULL;
huffman->rightson = NULL;
return huffman;
}
//初始化结点容器
void Compression::HuffmanTreeVector_Init()
{
for (map<unsigned char, int>::iterator it = weightmap.begin(); it != weightmap.end(); it++)
{
HuffmanTreeNode* huffman = MakehuffmanTreeNode(it->first);
container.push_back(huffman);
}
}
//建立哈夫曼树
void Compression::HuffmanTree_Init()
{
while (container.size() != 1) //也就是一直到生成根节点
{
//从头到尾开始排序,权重小的放底下
sort(container.begin(), container.end(), compare);
int sum = container[0]->Weight.second + container[1]->Weight.second;
HuffmanTreeNode* newhuffman = new HuffmanTreeNode; //新建哈夫曼结点
newhuffman->Weight.second = sum;
newhuffman->Weight.first = 0;
newhuffman->tag = 1; //新生成的标记为非叶子结点
newhuffman->leftson = container[0];
newhuffman->rightson = container[1];
container.erase(container.begin());
//删除后迭代器会顺移到下一位
container.erase(container.begin());
container.push_back(newhuffman);
}
}
//递归更新哈夫曼编码函数
void Compression::ZipPassword_Init(HuffmanTreeNode* &root, string& password)
{
if (root != NULL && !root->tag)
{
root->zippassword = password;
passwordmap[root->Weight.first] = password;
}
if (root->leftson != NULL)
{
//向左分支设为0
ZipPassword_Init(root->leftson, password += "0");
password.pop_back();
}
if (root->rightson != NULL)
{
//向右分支设为1
ZipPassword_Init(root->rightson, password+="1");
password.pop_back();
}
}
//压缩函数
void Compression::zip(QString path)
{
clock_t begin=clock(); //记录开始时间
QFile openfile(path); //创建QFile
if(!openfile.open(QIODevice::ReadOnly)) //打开文件,若不成功,发射出错信号,结束
{
QMessageBox::information(NULL,QString("警告"),QString("文件打开失败"));
emit error();
return;
}
Weightmap_Init(openfile); //权重映射初始化
emit mysignal(10); //更新进度条
HuffmanTreeVector_Init(); //哈夫曼结点容器初始化
emit mysignal(20);
HuffmanTree_Init(); //构建哈夫曼树
emit mysignal(30);
string empty="";
ZipPassword_Init(container[0],empty); //哈夫曼编码映射初始化
emit mysignal(40);
BinaryString_Init(); //获取二进制串
emit mysignal(50);
path+=".HuffmanZip"; //压缩后的文件格式后缀
openfile.close(); //关闭openfile
QFile savefile(path); //创建新的Qfile进行压缩文件的写入
savefile.open(QIODevice::WriteOnly); //打开
QDataStream out(&savefile); //利用QdataStream进行接下来的操作
int size = passwordmap.size();
if (size == 256)
size = 0; //因为256无法用一个字节保存
int length = 0;
out<<size; //传入哈夫曼编码映射数量
length++;
double k=1;
//迭代器
for (map<unsigned char, string>::iterator it = passwordmap.begin(); it != passwordmap.end(); it++)
{
emit mysignal(50+double(25*k++)/passwordmap.size());
int first = it->first;
out<<first; //传入key值
length++;
string second = it->second;
int size = second.size();
out<<size; //传入value值的长度
length++;
int n = 8 - second.size() % 8;
if (n)
{
second.append(n, '0'); //补0
}
for (int i = 0; i < second.size(); i += 8)
{
string k = second.substr(i, 8);
int temp = binarystringtoint(k);
unsigned char ch = temp;
out<<ch; //传入value值
length++;
}
}
int n = 8 - binary_string.size() % 8;
if (n)
{
binary_string.append(n, '0');
}
length++;
int totalbitsize = binary_string.size() / 8;
for (int i = 0; i < binary_string.size(); i += 8)
{
emit mysignal(75+double(25*i)/binary_string.size());
//分8个字节依次传入
string k = binary_string.substr(i, 8);
int temp = binarystringtoint(k);
unsigned char ch = temp;
out<<ch;
length++;
}
unsigned char temp=n;
out<<temp; //传入补0数量
length++;
emit mysignal(100);
int newlength=savefile.size();
savefile.close();
clock_t end=clock(); //结束时间
//弹窗提示本次压缩情况
QString tip("理论压缩比:");
tip+=QString::number(double(totalbitsize * 100) / source_string.size());
tip+="%,实际压缩比:";
tip+=QString::number(double(newlength * 100) / source_string.size());
tip+="%,压缩用时:";
tip+=QString::number(double(end-begin)/CLOCKS_PER_SEC);
tip+="s";
QMessageBox::about(this,"压缩说明",tip);
//结束后的清空处理
weightmap.clear();
passwordmap.clear();
source_string.clear();
binary_string.clear();
Delete(container[0]);
container.clear();
}
//解压函数
void Compression::unzip(QString path)
{
clock_t begin=clock(); //获取解压开始时间
if(path.right(11)!=".HuffmanZip")
没有合适的资源?快使用搜索试试~ 我知道了~
C++ QT实现类似于Bandizip解压缩的功能
共8个文件
cpp:3个
h:2个
pro:1个
需积分: 0 2 下载量 72 浏览量
2023-04-22
15:47:50
上传
评论
收藏 10KB ZIP 举报
温馨提示
Qt编写简易的解压缩图形界面,选择文件 ——> 选择压缩文件或解压文件 ——> 开始解压缩并显示进度条 ——> 放到指定文件路径下。采用树形结构存放数据,构造哈夫曼树(即最优编码树),实现解压缩功能。
资源推荐
资源详情
资源评论
收起资源包目录
解压缩.zip (8个子文件)
mainwindow.h 757B
compression.h 2KB
Compression.pro.user 24KB
mainwindow.cpp 2KB
main.cpp 183B
mainwindow.ui 4KB
Compression.pro 1KB
compression.cpp 10KB
共 8 条
- 1
资源评论
YJzj0610_
- 粉丝: 0
- 资源: 3
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功