使用haffman(哈夫曼)编码的简单压缩软件
2013-12-21 15:13
309 查看
限制只能操作1Mb以内的文件
学习haffman编码时写的软件,挂出来分享下下~
同样学习haffman编码的同学可以参考~~也希望大家帮助我改正错误~~
by 小夜
学习haffman编码时写的软件,挂出来分享下下~
同样学习haffman编码的同学可以参考~~也希望大家帮助我改正错误~~
by 小夜
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> using namespace std; int getbit(int c,int w) //获取二进制数c的第w位 { return (c>>w)&1; } class tree{ //用来生成haffman树,并记录haffman编码与字符的对应关系 public: int f; //字符频率 char ch; //字符 int code; //字符编码 int c_len; //编码长度 tree *left,*right; //左右子树 tree() //构造 { f=c_len=code=0; left=right=0; } ~tree() //析构 { if(left)delete left; if(right)delete right; } void preorder(int c,int len) //先序遍历,生成haffman编码 { code=c; c_len=len; if(left)left->preorder(c<<1,len+1); if(right)right->preorder((c<<1)|1,len+1); } }; class haffman{ //实现压缩与解压 char rfile[100]; //读入文件名 char zfile[100]; //压缩后文件名(读入文件后自动生成) char cfile[100]; //编码文件名 (读入文件后自动生成) tree *ba[551]; //基础字符编码树 tree *pt; //haffman树 根结点(供删除haffman树,清理内存) int b_len; //基础字符树个数 char *buffer,*r; //缓冲区,读入文件内容 int lenth; //读入内容长度 int max_bu,bu; //最大缓冲区段基值,偏移量 int max_bit; //最长haffman编码倍数(没有用到) public: haffman() //构造 { pt=0; buffer=new char[1024*1024]; r=new char[1024*1024]; memset(ba,0,sizeof(ba)); } ~haffman() //析构 { delete buffer; delete r; delete pt; } void read(); //读入文件内容到 r void calfreq(); //计算字符出现频率,保存在ba基础字符树中 void qs(tree *a[],int,int);//对字符树按频率进行排序 void makeh(); //生成haffman树,并获得基础字符的haffman编码 void wbit(int i); //向缓冲区写入一个字节 void zip(); //压缩 void write(); //写入文件缓冲区中的内容 void savecode(); //保存haffman编码和缓冲区大小,供解压用 void readbuffer(); //读入压缩文件内容到缓冲区 void readcode(); //读取haffman编码和缓冲区大小,供解压用 void unzip(); //解压并保存文件 void show(); //显示基础字符的haffman编码 调试用 void showbuffer(); //输出压缩后缓冲区内容的二进制编码 调试用 }; void haffman::read() //读入文件内容到 r { FILE *pf; int n=0; cout<<"打开文件: ";cin>>rfile; pf=fopen(rfile,"rb"); if(pf==0) { cout<<"文件打开失败!"<<endl; return; } strcpy(cfile,rfile); while(cfile !='.'&&cfile )++n; strcpy(cfile+n,".cod"); //自动生成保存编码的文件名 char *s=r; n=0; lenth=0; do { n=fread(s,sizeof(char),1024,pf); lenth+=n; if(lenth>1024*1024) { lenth=1024*1024; break; } s+=n; }while(n==1024); fclose(pf); } void haffman::qs(tree *a[],int b,int e) //排序,供生成haffman树 { if(b>=e)return ; tree *t; int k=a[b]->f,l=b,r=e; while(l<r) { while(l<r&&a[r]->f>=k)r--; t=a[l];a[l]=a[r];a[r]=t; while(l<r&&a[l]->f<k)l++; t=a[l];a[l]=a[r];a[r]=t; } a[r]=a[l]; qs(a,b,r-1); qs(a,r+1,e); } void haffman::calfreq() //计算频率,供生成haffman树 { b_len=0; char *s=r; for(int i=0;i<lenth;++i) //计算频率 { int j,ok=1; for(j=0;ba[j];++j) { if(ba[j]->ch==*s) { ba[j]->f++; ok=0; break; } } if(ok) { ba[j]=new tree; ba[j]->f=1; ba[j]->ch=*s; ++b_len; } ++s; } } void haffman::makeh() //生成haffman树并先序遍历获得haffman编码 { tree *tr[b_len]; memcpy(tr,ba,sizeof(tree*)*b_len); int i=0; if(pt)delete pt; while(i<b_len-1) //生成树 { qs(tr,i,b_len-1); pt=new tree; pt->f=tr[i]->f+tr[i+1]->f; pt->left=tr[i]; pt->right=tr[i+1]; tr[i+1]=pt; ++i; } pt->preorder(0,0);//获得haffman编码 } void haffman::wbit(int i) //向缓冲区写入一个字节 { buffer[max_bu]=buffer[max_bu]|(i<<bu); ++bu; if(bu>=8) //自动增加缓冲区大小 { bu=0; ++max_bu; } } void haffman::zip() //压缩字符串到缓冲区 { max_bu=bu=0; char *s=r; for(int i=0;i<lenth;++i) //压缩内容到buffer,直到 r 内容结束 { int j; for(j=0;j<b_len;++j) { if(ba[j]->ch==*s)break; } for(int k=ba[j]->c_len-1;k>=0;--k) { wbit(1&(ba[j]->code>>k)); } ++s; } } void haffman::write() //缓冲区写入文件 { FILE *pf; char s[100]; cout<<"保存为: ";cin>>s; int n=0; strcpy(cfile,s); while(cfile !='.'&&cfile )++n; strcpy(cfile+n,".cod"); //自动生成保存编码的文件名 pf=fopen(s,"wb"); if(pf==0) { cout<<"文件打开失败!"<<endl; return; } for(int i=0;i<=max_bu;++i) { fputc(buffer[i],pf); } fclose(pf); } void haffman::savecode() { FILE *pf; pf=fopen(cfile,"w"); if(pf==0) { cout<<"文件打开失败!"<<endl; return; } fprintf(pf,"%d %d\n",max_bu,bu);//保存缓冲区大小 for(int i=0;i<b_len;++i)//保存字符 编码 编码长度 { fprintf(pf,"%d %d %d\n",ba[i]->ch,ba[i]->code,ba[i]->c_len); } fclose(pf); } void haffman::readbuffer() //读取文件内容到缓冲区 { read(); memcpy(buffer,r,lenth*sizeof(char)); } void haffman::readcode() { FILE *pf; pf=fopen(cfile,"r"); if(pf==0) { cout<<"文件打开失败!"<<endl; return; } b_len=0; fscanf(pf,"%d %d",&max_bu,&bu); //读取缓冲区大小 while(!feof(pf)) { ba[b_len]=new tree; //读取字符 编码 编码长度 if(fscanf(pf,"%d %d %d",&ba[b_len]->ch,&ba[b_len]->code,&ba[b_len]->c_len)==3)++b_len; } fclose(pf); } void haffman::unzip() { int seg=0,i=0; //记录目前读取位置 int c=0,len=0; char ufile[100]; // show(); // showbuffer(); FILE *pf; cout<<"解压为: ";cin>>ufile; pf=fopen(ufile,"wb"); if(pf==0) { cout<<"文件打开失败!"<<endl; return; } while(seg<max_bu||(seg==max_bu&&i<bu))//解压,直到缓冲区结束 { c=c<<1; c|=1&(buffer[seg]>>i); ++i; if(i>=8) { i=0; ++seg; } ++len; for(int j=0;j<b_len;++j) { if(len==ba[j]->c_len&&c==ba[j]->code) { len=c=0; // putchar(ba[j]->ch); fputc(ba[j]->ch,pf); break; } } } fclose(pf); } void haffman::show() //显示字符对应haffman编码 调试用 { for(int i=0;i<b_len;++i) //按 字符:编码长度:编码 显示字符对应haffman编码 { int len=ba[i]->c_len; cout<<ba[i]->ch<<": "<<len<<": "; for(int j=len-1;j>=0;--j) { cout<<(1&(ba[i]->code>>j)); }cout<<endl; } } void haffman::showbuffer() //显示缓冲区中的二进制编码 调试用 { int seg=0,i=0; while(seg<max_bu||(seg==max_bu&&i<bu)) //判读是否到缓冲末尾 { cout<<(1&(buffer[seg]>>i)); ++i; if(i>=8) { i=0; ++seg; cout<<" "; } } } int menu() //菜单 { haffman a; int n; cout<<endl; cout<<"1.压缩"<<endl; cout<<"2.解压"<<endl; cout<<"3.退出"<<endl; cout<<"请选择: "; cin>>n; switch(n) { case 1: //压缩过程 a.read(); //读入文件 a.calfreq(); //获取字符出现频数 a.makeh(); //生成字符haffman编码 a.zip(); //压缩字符,存入缓冲区 a.write(); //将缓冲区内容写入文件 a.savecode(); //保存haffman编码和缓冲区大小 ,供解压时使用 break; case 2: a.readbuffer(); //将文件内容读入缓冲区 a.readcode(); //读入保存的编码和缓冲区大小 a.unzip(); //解压并保存文件 break; default: return 0; } return 1; } int main() { while(menu()); return 0; }
相关文章推荐
- 使用haffman(哈夫曼)编码的简单压缩软件
- chm格式电子书另类反编译法:使用压缩软件7Z简单实现CHM电子书反编译 | 志文工作室
- 常用编码软件简单使用记录 1 : 自主编码器
- 常用编码软件简单使用记录 2 : 非自主编码器
- 常用编码软件简单使用记录 1 : 自主编码器
- 常用编码软件简单使用记录 2 : 非自主编码器
- sharpziplib是一个不错的在线压缩软软件.用VB.net简单写了个使用代码!
- 常用编码软件简单使用记录 2 : 非自主编码器
- 常用编码软件简单使用记录 2 : 非自主编码器
- Java---软件试用次数(Properties类的简单使用)
- 使用游长编码对字符串压缩 Run Length编码示例
- python中使用文件的读取编码问题和简单正则使用(一)
- iPhone 实用技巧 之 快速使用iTools安装ipa软件。本节简单介绍如何使用iTools安装在iPhone上安装ipa软件,具体如下
- 使用elecard stream软件获取编码码流每帧的大小
- Python3zip压缩解压简单使用
- iOS 多线程 GCD的简单使用——iOS 编码复习(七)(多线程5)
- linux下简单而又快捷的压缩软件p7zip
- 哈夫曼压缩原理及其简单实现
- IAR for 430软件的简单使用
- python中使用文件的读取编码问题和简单正则使用(二)