Huffman编码实现文件的压缩与解压缩。
以前没事的时候写的,c++写的,原理很简单,代码如下:
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
//#include <bitset>
#include <fstream>
#include <ctime> const int maxCodeNum = ; using namespace std; //哈夫曼树的树节点
struct HaffTreeNode{
HaffTreeNode * lNode;
HaffTreeNode * rNode;
string haffCode;
int value;
int alpha;
HaffTreeNode()
:lNode(NULL), rNode(NULL), haffCode(""), value(), alpha(){;}
}; //链表节点,用于生成哈夫曼树
struct ListNode{
struct HaffTreeNode HaffTreeNode;
ListNode *nextListNode;
ListNode()
:nextListNode(NULL){;}
}; //用与保存输入文件统计信息的hash表
typedef struct HashTable{
int value;
int alpha;
HashTable()
:value(), alpha(){}
//比较函数用于排序使用
inline friend int operator-(const HashTable & a, const HashTable & b){
return a.value - b.value;
}
} HashTable;
HashTable charHashTable[maxCodeNum]; //排序使用的比较大小的函数
int hashComp(const void * a, const void * b)
{
return *((HashTable *)a) - *((HashTable *)b);
} //创建一个哈夫曼树
HaffTreeNode * createHaffTreeNodeTree(HashTable table[])
{
ListNode *root = new ListNode;
ListNode *next = root;
for(int i = ; /*i < maxCodeNum - 1*/; ++i){
if(table[i].value == )//如果对应的码不为0,就为其分配一个树节点
continue;
next->HaffTreeNode.alpha = table[i].alpha;
next->HaffTreeNode.value = table[i].value;
if(i ==maxCodeNum - )
break;
next->nextListNode = new ListNode;
next = next->nextListNode;
} while(root->nextListNode != NULL){
ListNode * currNode = new ListNode;
currNode->HaffTreeNode.value = root->HaffTreeNode.value + root->nextListNode->HaffTreeNode.value;
currNode->HaffTreeNode.lNode = &(root->HaffTreeNode);
currNode->HaffTreeNode.rNode = &(root->nextListNode->HaffTreeNode);
root = root->nextListNode->nextListNode; //概率最小的两个码相加组成一个新的节点 ListNode * nextNode = root;
ListNode * prevNode = NULL;
while(nextNode != NULL && currNode->HaffTreeNode.value > nextNode->HaffTreeNode.value){
prevNode = nextNode;
nextNode = nextNode->nextListNode;
} if(prevNode == NULL){//将这个新的节点插入到所有节点之前(currNode目前还是最小的)
currNode->nextListNode = nextNode;
root = currNode;
}else{//插入到节点中间或者节点之后的位置
prevNode->nextListNode = currNode;
currNode->nextListNode = nextNode;
}
}//在这个list中所有的元素遍历完成之后返回
return &(root->HaffTreeNode);//返回书的根节点的哈弗满节点,这个节点已经构造成为了一棵树
} string huffmanCodeTable[maxCodeNum];
string haffCode; //给哈夫曼树编码
void createHaffmanTable(HaffTreeNode * root)
{
if(root->lNode == NULL && root->rNode == NULL){
huffmanCodeTable[root->alpha] = haffCode;
haffCode.erase(haffCode.length() - );
return;
}//给各个节点赋予相应的哈夫曼编码
haffCode.append("");
createHaffmanTable(root->lNode); haffCode.append("");
createHaffmanTable(root->rNode); if(!haffCode.empty()){
haffCode.erase(haffCode.length() - );
}
return;
} //将生成的二进制长串编码转换成字符用于存储在压缩文件中
unsigned char StrToBin(string str)
{
unsigned int ans =;
int tmpNum = atoi(str.c_str());
int multiNum = ;
while(tmpNum != ){
ans += tmpNum%*multiNum;
tmpNum/=;
multiNum *= ;
}
return (unsigned char) ans;
} //用于将压缩文件的字符转换成huffman编码
string BinToStr(unsigned char c)
{
string tmpNumStr;
while(c != ){
tmpNumStr.insert(tmpNumStr.begin(), (unsigned char)(c% + ''));
c /= ;
}
if(tmpNumStr.length() < ){
tmpNumStr.insert(tmpNumStr.begin(), - tmpNumStr.length(), '');
}
return tmpNumStr;
} //下面是将huffman码译成原字符的程序
char huffDecode(HaffTreeNode * root, string & code)
{
unsigned int i;
for( i = ; i < code.length(); ++i){
if(root->alpha == )
root = (code[i] - '')?root->rNode:root->lNode;
else{
code.erase(, i);
return root->alpha;
}
}
if(root->alpha !=){
code.erase(, i);
return root->alpha;
}
code.clear();
return '\0';
} int main(int argc, char ** argv)
{
if(argc != ){
printf("Error number of arguments!\n");
}
FILE * fin = fopen(argv[], "r");
int c = ;
while((c = fgetc(fin)) != EOF && c != '\n'){
putchar(c);
putchar('*');
charHashTable[c].alpha = c;
charHashTable[c].value++;
} qsort(charHashTable, sizeof(charHashTable)/sizeof(charHashTable[]),
sizeof(charHashTable[]), hashComp);
/*建立有关本文件的huffman树*/
HaffTreeNode * haffTreeRoot = createHaffTreeNodeTree(charHashTable);
createHaffmanTable(haffTreeRoot); cout << "Char\tTimes\tCodes";
for(int i = ; i < maxCodeNum; ++i){
if(charHashTable[i].value != ){
cout << (char)charHashTable[i].alpha << "\t" << charHashTable[i].value
<< "\t" << huffmanCodeTable[charHashTable[i].alpha] << "\n";
}
} FILE * fout;
if((fout = fopen(argv[], "w")) == NULL){
perror("open output file error!\n");
}
rewind(fin);
string buf; while((c = fgetc(fin)) != EOF){ /*将文件通过huffman码转来进行压缩*/
//printf("The char is %c ", c);
buf += huffmanCodeTable[c];
cout << buf << endl;
if(buf.length() > ){ //当转换的字符得到的huffman码达到8的时候转换成一个字符填入目标文件
fputc(StrToBin(buf.substr(, )), fout);
buf.erase(, );
}
} int leftZero = ; //保存不到8位的余留位的个数
if(!buf.empty()){
buf.append((leftZero = - buf.length()), '');
fputc(StrToBin(buf), fout);
} if(fclose(fin) == -)
perror("close file error!\n");
if(fclose(fout) == -)
perror("close file error!\n"); if((fin = fopen(argv[], "rb")) == NULL)//打开压缩文件,开始解码
perror("Open file error!\n");
if((fout = fopen("huffmanDecompose.txt", "w")) == NULL)
perror("Open file error!\n"); //开始解码
int bin;
buf.clear();
while((bin = fgetc(fin)) != EOF){
buf.append(BinToStr(bin));
} while(buf.length() - leftZero != && !buf.empty()){
fputc(huffDecode(haffTreeRoot, buf), fout);
}
if(fclose(fin) != )
perror("close file error!\n");
if(fclose(fout) != )
perror("close file error!\n");
return ;
}
./a.out file1 file2
file1:输入文件
file2:输出文件(压缩后)
要锁完成后会将文压缩文件解压到huffmanDecompose.txt这个文件中
Huffman编码实现文件的压缩与解压缩。的更多相关文章
- C# 下利用ICSharpCode.SharpZipLib.dll实现文件/目录压缩、解压缩
ICSharpCode.SharpZipLib.dll下载地址 1.压缩某个指定文件夹下日志,将日志压缩到CompressionDirectory文件夹中,并清除原来未压缩日志. #region 压缩 ...
- Linux之文件的压缩与解压缩
压缩格式 .zip,.rar,.7z,.tar,.gz,.xz,.bz2,.tar.gz,.tar.xz,.tar.bz2,其中,形如*.tar.gz为tar打包,gz压缩的文件 zip压缩打包程序 ...
- Linux文件打包压缩、解压缩、备份命令使用方法(转载)
对于刚刚接触Linux的人来说,一定会给Linux下一大堆各式各样的文件名给搞晕.别个不说,单单就压缩文件为例,我们知道在Windows下最常见的压缩文件就只有两种,一是,zip,另一个是.rar.可 ...
- java实现单个或多个文件的压缩、解压缩 支持zip、rar等格式
代码如下: package com.cn.util; import java.io.BufferedInputStream; import java.io.File; import java.io.F ...
- Linux下文件的压缩与解压缩
一.zip格式 zip可能是目前使用的最多的文档压缩格式.它最大的优点就是在不同的操作系统平台上使用.缺点就是支持 的压缩率不是很高,而tar.gz和tar.bz2在压缩率方面做得非常好. 我们可以使 ...
- C# 文件/文件夹压缩解压缩
项目上用到的,随手做个记录,哈哈. 直接上代码: using System; using System.Data; using System.Configuration; using System.C ...
- Linux下文件的压缩与打包
一.Linux下常见的文件压缩命令: 在Linux的环境中,压缩文件的扩展名大多是:『*.tar, *.tar.gz, *.tgz, *.gz, *.Z, *.bz2』,为什么会有这样的扩展名呢? 这 ...
- C#压缩文件,C#压缩文件夹,C#获取文件
using System; using System.Data; using System.Configuration; using System.Collections.Generic; using ...
- Jcompress: 一款基于huffman编码和最小堆的压缩、解压缩小程序
前言 最近基于huffman编码和最小堆排序算法实现了一个压缩.解压缩的小程序.其源代码已经上传到github上面: Jcompress下载地址 .在本人的github上面有一个叫Utility的re ...
随机推荐
- 七牛云 如何配置域名的 CNAME
CNAME 简介 CNAME 即指别名记录,也被称为规范名字.这种记录允你将多个名字映射到同一台计算机. 当需要将域名指向另一个域名,再由另一个域名提供 ip地址,就需要添加 CNAME 记录. 为什 ...
- linux 学习笔记之文件与管理
前言: 对于windows来说,文件的系统管理都是非常简单的(这个应该有一个捂脸),通常就是重命名,复制,移动,删除,查看文件属性,查看文件内容,寻找文件.其实在图形化行中的linux也是有这样子功能 ...
- Django相关介绍
先认识一下MVC框架 MVC的框架模式,即模型M,视图V和控制器C.他们之间以一种插件似的,松耦合的方式连接在一起. Model(模型)是应用程序中用于处理应用程序数据逻辑的部分. 通常模型对象负责在 ...
- 关于 sql server 基本使用的建议
1. 把现有的表插入到新表,(表不能存在),为表备份. -- select * into NewTable from OldTable (NewTable 在select 查询的 ...
- 利用反射快速给Model实体赋值
试想这样一个业务需求:有一张合同表,由于合同涉及内容比较多所以此表比较庞大,大概有120多个字段.现在合同每一次变更时都需要对合同原始信息进行归档一次,版本号依次递增.那么我们就要新建一张合同历史表, ...
- LeetCode:翻转二叉树【226】
LeetCode:翻转二叉树[226] 题目描述 翻转一棵二叉树. 示例: 输入: 4 / \ 2 7 / \ / \ 1 3 6 9 输出: 4 / \ 7 2 / \ / \ 9 6 3 1 题目 ...
- OpenOCD SWD调试stm32f0
参考:http://www.stmcu.org.cn/module/forum/thread-610998-1-2.html
- canvas笔记1
w3c定义: <canvas> 标签定义图形,比如图表和其他图像. <canvas> 标签只是图形容器,您必须使用脚本来绘制图形. canvas 对象 属性: width he ...
- Entity FrameWork Code First 之 MVC4 数据库初始化策略用法
通过启用迁移和更新数据库可以很容易的生成一张表.但是对数据库修改之后,通过数据迁移就没那么好实现了. 这里用到数据库生成策略,进行对数据库操作: 一.3种主要数据库生成策略 1 CreateDatab ...
- systemverilog interface杂记
随着IC设计复杂度的提高,模块间互联变得复杂,SV引入接口,代表一捆连线的结构. Systemverilog语法标准,新引入一个重要的数据类型:interface. interface主要作用有两个: ...