huffman编码译码实现文件的压缩与解压.
利用哈夫曼编码实现压缩和解压缩
利用哈夫曼编码实现压缩和解压缩1.问题描述利用哈夫曼编码,实现压缩和解压缩的数据元素具有如下形式:结点:weight:存储结点的权值parent:是结点双亲在向量中的下标lchild:结点的左儿子向量下标rchild:结点右儿子向量下标bits:位串,存放编码ch:字符start:编码在位串中的起始位置文件操作记录:b:记录字符在数组中的位置count:字符出现频率(权值)lch、rch、parent:定义哈夫曼树指针变量bits[256]:定义存储哈夫曼编码的数组2.功能需求对于给定的一组字符,可以根据其权值进行哈夫曼编码,并能输出对应的哈夫曼树和哈夫曼编码;实现哈夫曼解码。
能够分析文件,统计文件中出现的字符,再对文件进行编码,实现文件的压缩和解压缩,能够对于文件的压缩,比例进行统计,能够打印文件。
3.实现要点(1)构造哈弗曼树过程中,首先将初始森林的各根结点的双亲和左、右儿子指针置-1;叶子在向量T的前n个分量中,构成初始森林的n个结点;对森林中的树进行n次合并,并产生n-1个新结点,依次放入向量T的第i个分量中。
(2)编码过程中,从叶子T[i]出发,利用双亲的指针找到双亲T[p];再根据T[p]的孩子指针可以知道T[i]是T[p]的左儿子还是右儿子,若是左儿子,则生成代码0,否则生成代码1;(3)在文件压缩和解压过程中,主要参考网上资料,每个步骤都基本理解,并注上了详细解析。
4.函数定义功能:输入权重,构造一棵哈弗曼树void huffman(hftree T){if(n<1 || n > m)return;int i,j,p1,p2;float small1,small2;//初始化cout<<"请输入叶子权重(5个):"<<endl;for(i=0; i<n; i++){T[i].parent = -1;T[i].lchild = T[i].rchild = -1;}//输入叶子权值for(i=0; i<n; i++){cin>>T[i].weight;}for(i=n; i<m; i++){p1 = p2 = -1;small1 = small2 = MAX_FLOAT;for(j=0; j<=i-1; j++){if(T[j].parent != -1)continue;if(T[j].weight < small1){small2 = small1;small1 = T[j].weight;p2 = p1;p1 = j;}else if(T[j].weight < small2){small2 = T[j].weight;p2 = j;}}T[p1].parent = T[p2].parent = i;T[i].parent=-1;T[i].lchild=p1;T[i].rchild=p2;T[i].weight=small1 + small2;}cout<<"创建成功!"<<endl;}功能:对哈弗曼树进行编码void encode(codelist codes, hftree T){int i,c,p,start;cout<<"请输入需要编码的字符(5个):"<<endl;for(i=0; i<n; i++){cin>>codes[i].ch;start=n;c=i;p=T[i].parent;while(p!=-1){start--;if(T[p].lchild==c) codes[i].bits[start]='0';else codes[i].bits[start]='1';c=p;p=T[p].parent;}codes[i].start=start;}cout<<"输入成功!:"<<endl;cout<<"编码表:"<<endl;for(int x=0; x<n; x++){cout<<codes[x].ch<<": ";for(int q=codes[x].start;q<n;q++) cout<<codes[x].bits[q];cout<<endl;}}函数功能:对哈弗曼树进行解码void decode(codelist codes,hftree T) {int i,c,p,b;int endflag;endflag=-1;i=m-1;while(cin>>b,b!=endflag){if(b==0) i=T[i].lchild;else i=T[i].rchild;if(T[i].lchild==-1){cout<<codes[i].ch;i=m-1;}}if(i!=m-1)cout<<"编码有错!\n";}功能:对文件进行压缩,统计压缩率void compress(){char filename[255],outputfile[255],buf[512];unsigned char c;long i,j,m,n,f;long min1,pt1,flength,length1,length2;double div;FILE *ifp,*ofp;cout<<"\t请您输入需要压缩的文件:";cin>>filename;ifp=fopen(filename,"rb");if(ifp==NULL){cout<<"\n\t文件打开失败!\n\n";return;}cout<<"\t请您输入压缩后的文件名:";cin>>outputfile;ofp=fopen(strcat(outputfile,".encode"),"wb");if(ofp==NULL){cout<<"\n\t压缩文件失败!\n\n";return;}flength=0;while(!feof(ifp)){fread(&c,1,1,ifp);header[c].count++; //字符重复出现频率+1flength++; //字符出现原文件长度+1}flength--;length1=flength; //原文件长度用作求压缩率的分母header[c].count--;for(i=0;i<512;i++){if(header[i].count!=0) header[i].b=(unsigned char)i;else header[i].b=0;header[i].parent=-1;header[i].lch=header[i].rch=-1; //对结点进行初始化}for(i=0;i<256;i++) //根据频率(权值)大小,对结点进行排序,选择较小的结点进树{for(j=i+1;j<256;j++){if(header[i].count<header[j].count){tmp=header[i];header[i]=header[j];header[j]=tmp;}}}for(i=0;i<256;i++) if(header[i].count==0) break;n=i; //外部叶子结点数为n个时,内部结点数为n-1,整个哈夫曼树的需要的结点数为2*n-1.m=2*n-1;for(i=n;i<m;i++) //构建哈夫曼树{min1=999999999; //预设的最大权值,即结点出现的最大次数for(j=0;j<i;j++){if(header[j].parent!=-1) continue;//parent!=-1说明该结点已存在哈夫曼树中,跳出循环重新选择新结点*/if(min1>header[j].count){pt1=j;min1=header[j].count;continue;}}header[i].count=header[pt1].count;header[pt1].parent=i; //依据parent域值(结点层数)确定树中结点之间的关系header[i].lch=pt1; //计算左分支权值大小min1=999999999;for(j=0;j<i;j++){if(header[j].parent!=-1) continue;if(min1>header[j].count){pt1=j;min1=header[j].count;continue;}}header[i].count+=header[pt1].count;header[i].rch=pt1; //计算右分支权值大小header[pt1].parent=i;}for(i=0;i<n;i++) //哈夫曼无重复前缀编码{f=i;header[i].bits[0]=0; //根结点编码0while(header[f].parent!=-1){j=f;f=header[f].parent;if(header[f].lch==j) //置左分支编码0{j=strlen(header[i].bits);memmove(header[i].bits+1,header[i].bits,j+1);//依次存储连接“0”“1”编码header[i].bits[0]='0';}else //置右分支编码1{j=strlen(header[i].bits);memmove(header[i].bits+1,header[i].bits,j+1);header[i].bits[0]='1';}}}fseek(ifp,0,SEEK_SET); //从文件开始位置向前移动0字节,即定位到文件开始位置fwrite(&flength,sizeof(int),1,ofp);fseek(ofp,8,SEEK_SET);buf[0]=0; //定义缓冲区,它的二进制表示00000000f=0;pt1=8;while(!feof(ifp)){c=fgetc(ifp);f++;for(i=0;i<n;i++){if(c==header[i].b) break;}strcat(buf,header[i].bits);j=strlen(buf);c=0;while(j>=8) //对哈夫曼编码位操作进行压缩存储{for(i=0;i<8;i++){if(buf[i]=='1') c=(c<<1)|1;else c=c<<1;}fwrite(&c,1,1,ofp);pt1++; //统计压缩后文件的长度strcpy(buf,buf+8); //一个字节一个字节拼接j=strlen(buf);}if(f==flength) break;}if(j>0) //对哈夫曼编码位操作进行压缩存储{strcat(buf,"00000000");for(i=0;i<8;i++){if(buf[i]=='1') c=(c<<1)|1;else c=c<<1;}fwrite(&c,1,1,ofp);pt1++;}fseek(ofp,4,SEEK_SET);fwrite(&pt1,sizeof(long),1,ofp);fseek(ofp,pt1,SEEK_SET);fwrite(&n,sizeof(long),1,ofp);for(i=0;i<n;i++){fwrite(&(header[i].b),1,1,ofp);c=strlen(header[i].bits);fwrite(&c,1,1,ofp);j=strlen(header[i].bits);if(j%8!=0) //若存储的位数不是8的倍数,则补0 {for(f=j%8;f<8;f++)strcat(header[i].bits,"0");}while(header[i].bits[0]!=0){c=0;for(j=0;j<8;j++) //字符的有效存储不超过8位,则对有效位数左移实现两字符编码的连接{if(header[i].bits[j]=='1') c=(c<<1)|1; //|1不改变原位置上的“0”“1”值else c=c<<1;}strcpy(header[i].bits,header[i].bits+8); //把字符的编码按原先存储顺序连接fwrite(&c,1,1,ofp);}}length2=pt1--;div=((double)length1-(double)length2)/(double)length1; //计算文件的压缩率fclose(ifp);fclose(ofp);printf("\n\t压缩文件成功!\n");printf("\t压缩率为 %f%%\n\n",div*100);return;}函数功能:对文件解压缩void uncompress(){char filename[255],outputfile[255],buf[255],bx[255];unsigned char c;long i,j,m,n,f,p,l;long flength;FILE *ifp,*ofp;cout<<"\t请您输入需要解压缩的文件:";cin>>filename;ifp=fopen(strcat(filename,".encode"),"rb");if(ifp==NULL){cout<<"\n\t文件打开失败!\n";return;}cout<<"\t请您输入解压缩后的文件名:";cin>>outputfile;ofp=fopen(outputfile,"wb");if(ofp==NULL){cout<<"\n\t解压缩文件失败!\n";return;}fread(&flength,sizeof(long),1,ifp); //读取原文件长度,对文件进行定位fread(&f,sizeof(long),1,ifp);fseek(ifp,f,SEEK_SET);fread(&n,sizeof(long),1,ifp);for(i=0;i<n;i++){fread(&header[i].b,1,1,ifp);fread(&c,1,1,ifp);p=(long)c; //读取原文件字符的权值header[i].count=p;header[i].bits[0]=0;if(p%8>0) m=p/8+1;else m=p/8;for(j=0;j<m;j++){fread(&c,1,1,ifp);f=c;itoa(f,buf,2); //将f转换为二进制表示的字符串f=strlen(buf);for(l=8;l>f;l--){strcat(header[i].bits,"0");}strcat(header[i].bits,buf);}header[i].bits[p]=0;}for(i=0;i<n;i++) //根据哈夫曼编码的长短,对结点进行排序{for(j=i+1;j<n;j++){if(strlen(header[i].bits)>strlen(header[j].bits)){tmp=header[i];header[i]=header[j];header[j]=tmp;}}}p=strlen(header[n-1].bits);fseek(ifp,8,SEEK_SET);m=0;bx[0]=0;while(1) //通过哈夫曼编码的长短,依次解码,从原来的位存储还原到字节存储{while(strlen(bx)<(unsigned int)p){fread(&c,1,1,ifp);f=c;itoa(f,buf,2);f=strlen(buf);for(l=8;l>f;l--) //在单字节内对相应位置补0{strcat(bx,"0");}strcat(bx,buf);}for(i=0;i<n;i++){if(memcmp(header[i].bits,bx,header[i].count)==0) break;}strcpy(bx,bx+header[i].count);c=header[i].b;fwrite(&c,1,1,ofp);m++; //统计解压缩后文件的长度if(m==flength) break; //flength是原文件长度}fclose(ifp);fclose(ofp);cout<<"\n\t解压缩文件成功!\n";if(m==flength) //对解压缩后文件和原文件相同性比较进行判断(根据文件大小)cout<<"\t解压缩文件与原文件相同!\n\n";else cout<<"\t解压缩文件与原文件不同!\n\n";return;}5、总结和体会本次大作业与C++大作业有所不同,主要是利用构造数据结构解决问题,C++大作业主要体现类和文件读写功能。
Huffman的应用之文件压缩与解压缩
Huffman的应用之文件压缩与解压缩最近这段时间一直在学习树的这种数据结构,也接触到了Huffman树以及了解了什仫是Huffman编码,而我们常用的zip压缩也是利用的Huffman编码的特性,那仫是不是可以自己实现一个文件压缩呢?当然可以了.在文件压缩中我实现了Huffman树和建堆Heap的代码,zip压缩的介绍>下面开始介绍自己实现的文件压缩的思路和问题...1).统计>读取一个文件统计这个文件中字符出现的次数.2).建树>以字符出现的次数作为权值使用贪心算法构建Huffman树(根据Huffman树的特性>字符出现次数多的一定靠近根结点,出现次数少的一定远离根结点).3).生成Huffman编码>规则左0右1.4).压缩>再次读取文件,根据生成的Huffman编码压缩文件.5).生成配置文件>将字符以及字符出现的次数写进配置文件中.6).解压缩>利用配置文件还原出Huffman树,根据压缩文件还原出原文件.7).测试>判断解压是否正确需要判断原文件和解压缩之后的文件是否相同,利用Beyond Compare软件进行对比.下面是我举的一个简单的范例,模拟压缩和解压缩的过程,希望有读者有帮助利用Beyond Compare软件进行对比>在实现中出现了很多的问题,下面我提出几个容易犯的问题,仅供参考1).在使用贪心算法构建Huffman树的时候,如果我们以unsigned char一个字节来存储它总共有2^8=256个字符,如果将所有的字符都构建Huffman树,这不仅降低了效率还将分配极大的内存.所以我设立了非法值这个概念,只有当字符出现的次数不为0的时候才将该字符构建到Huffman树中.2).在写压缩文件的时候我们是将字符对应的Huffman编码转化为对应的位,每当填满一个字节(8位)后再写入压缩文件中.如果最后一个字节没有填满我们就将已经填的位移位空出后几个位置,将未满的位置补0补满一个字节再写入压缩文件中.3).如果我们将源文件压缩之后再去解压,因为你的Huffman树和Huffman编码都是在压缩函数中得到的,此时再去解压那仫你的Huffman编码以及不存在了该如何去还原文件呢?这就是为什仫要生成配置文件的原因了,在配置文件中写入了字符以及字符出现的次数.在解压缩中根据配置文件构建新的Huffman树.4).由压缩文件还原文件的时候如何知道压了多少个字符呢?也就是说因为我们在压缩的时候最后一个字节是补了0的在解压缩的时候可能会把这个补的位当成字符的编码来处理.一种想法是在统计字符出现的次数的时候设置一个变量,每读取一个字符该变量就加1,最后将该变量写进配置文件中.另外一种想法就是根据根结点的权值,通过上述简单的实例观察可知根结点权值中的_count就是字符出现的次数.解决了以上几个问题,我的程序已经可以压缩那256个字符并正确的还原了,那仫如果是大文件或者是汉字,图片以及音频视频呢?1).因为有些特殊的字符编码,所以我们统计字符出现的次数的时候应该用的是unsigned char,刚开始我用的文件结束标志是EOF在ASII中它的编码是-1此时已经不可以用EOF来判断是否文件结束了,所以我用了feof这个函数来判断文件是否结束.2).统计字符出现次数应该用的类型是long long,这就解决了大文件的压缩和解压缩的问题了.3).因为汉字,图片,视频这些在内存中是以二进制的形式存在的,所以我们将以文本形式打开读或者写的修改为以二进制的形式读或者写.为了验证大文件的压缩我找了一个8.09M的文件压缩之后是6.50M,并且可以正确还原.1).测试效率>2).利用Beyond Compare软件进行对比,如果一样说明压缩成功>[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片#define _CRT_SECURE_NO_W ARNINGS 1#pragma once#include "Heap.h"template<class T>struct HuffmanTreeNode{T _weight;HuffmanTreeNode<T> *_left;HuffmanTreeNode<T> *_right;HuffmanTreeNode<T> *_parent;HuffmanTreeNode(const T& w=T()):_weight(w),_left(NULL),_right(NULL),_parent(NULL){}};template<class T>class HuffmanTree{typedef HuffmanTreeNode<T> Node;public:HuffmanTree():_root(NULL){}HuffmanTree(const T* a,size_t size):_root(NULL){_root=_CreatHuffmanTree(a,size);}//将未出现的字符过滤出来,不构造堆HuffmanTree(const T* a,size_t size,const T& invalid){_root=_CreatHuffmanTree(a,size,invalid);}Node* GetRoot(){return _root;}~HuffmanTree(){_Destroy(_root);}protected:Node *_CreatHuffmanTree(const T* a,size_t size){struct NodeLess{bool operator()(Node *l,Node *r)const{return l->_weight < r->_weight;}};Heap<Node *,NodeLess> minHeap;//建立结点并放入vector中for (size_t i=0;i<size;++i){Node *tmp=new Node(a[i]);minHeap.Push(tmp);}//取出较小的两个结点作为左右孩子并构建父结点while (minHeap.Size() > 1){Node *left=minHeap.Top();minHeap.Pop();Node *right=minHeap.Top();minHeap.Pop();Node *parent=new Node(left->_weight + right->_weight);parent->_left=left;parent->_right=right;left->_parent=parent;right->_parent=parent;minHeap.Push(parent);}return minHeap.Top();}//思路类似不带过滤功能的Node *_CreatHuffmanTree(const T* a,size_t size,const T& invalid) {struct NodeLess{bool operator()(Node *l,Node *r)const{return l->_weight < r->_weight;}};Heap<Node *,NodeLess> minHeap;//建立结点并放入vector中for (size_t i=0;i<size;++i){if(a[i] != invalid){Node *tmp=new Node(a[i]);minHeap.Push(tmp);}}//取出较小的两个结点作为左右孩子并构建父结点while (minHeap.Size() > 1){Node *left=minHeap.Top();minHeap.Pop();Node *right=minHeap.Top();minHeap.Pop();Node *parent=new Node(left->_weight + right->_weight);parent->_left=left;parent->_right=right;left->_parent=parent;right->_parent=parent;minHeap.Push(parent);}return minHeap.Top();}void _Destroy(Node *&root)if(root == NULL)return ;Node *cur=root;if(cur){_Destroy(cur->_left);_Destroy(cur->_right);delete cur;cur=NULL;return ;}}protected:Node *_root;};void testHuffmanTree(){int a[]={0,1,2,3,4,5,6,7,8,9};int size=sizeof(a)/sizeof(a[0]);HuffmanTree<int> ht(a,size);}[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片#define _CRT_SECURE_NO_W ARNINGS 1#pragma once//利用仿函数的特性实现代码的复用性template<class T>struct Small{bool operator()(const T& l,const T& r){return l < r;}};template<class T>struct Large{bool operator()(const T& l,const T& r)return l > r;}};template<class T,class Compare=Large<T>> //缺省是建小堆class Heap{public:Heap(){}Heap(const T *a,int size){assert(a);_a.reserve(size);for (int i=0;i<size;++i){_a.push_back(a[i]);}//建堆的时候从倒数第一个非叶子结点开始.for (int j=(size-2)/2;j>=0;--j){_AdjustDown(j);}}void Push(const T& x){_a.push_back(x);_AdjustUp(_a.size()-1);}void Pop(){assert(!_a.empty());swap(_a[0],_a[_a.size()-1]);_a.pop_back();_AdjustDown(0);}size_t Size(){return _a.size();}bool Empty(){return _a.empty();const T& Top()const{assert(!_a.empty());return _a[0];}void Display(){for (size_t i=0;i<_a.size();++i){cout<<_a[i]<<" ";}cout<<endl;}protected:void _AdjustDown(int root){int parent=root;size_t child=2*root+1;while (child < _a.size()){Compare com;//child指向左右孩子中较大的那个数//if (child+1 < _a.size()// && _a[child+1] > _a[child])if(child+1 < _a.size()&& com(_a[child+1],_a[child])){child++;}//if (_a[child] > _a[parent])if(com(_a[child],_a[parent])){swap(_a[child],_a[parent]);parent=child;//初始的child默认指向左孩子child=2*parent+1;}elsebreak;}}void _AdjustUp(int child){while (child > 0){int parent=(child-1)/2;Compare com;//if (_a[child] > _a[parent])if(com(_a[child],_a[parent])){swap(_a[child],_a[parent]);child=parent;}else//插入的数据比父节点的数据域小break;}}protected:vector<T> _a;};//利用堆解决优先级队列的问题template<class T,class Compare=Large<T>>class PriorityQueue{public:PriorityQueue(int *a,int size):_pq(a,size){}void Push(const T& x){_pq.Push(x);}void Pop(){_pq.Pop();}const T& Top()const{return _pq.Top();}void Display(){_pq.Display();}protected:Heap<T,Compare> _pq;};[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片#define _CRT_SECURE_NO_W ARNINGS 1#pragma once#include "HuffmanTree.h"typedef long long Type;struct CharInfo{unsigned char _ch; //出现的字符Type _count; //统计次数string _code; //Huffman编码CharInfo(Type count=0):_ch(0),_count(count),_code(""){}//重载对应的操作符CharInfo operator + (const CharInfo& fc)const{return CharInfo(_count + fc._count);}bool operator != (const CharInfo fc)const{return _count != fc._count;}bool operator < (const CharInfo& fc)const{return _count < fc._count;}};class FileCompress{public://默认的构造函数FileCompress(){for(size_t i=0;i<256;++i){_infos[i]._ch=i;}}string Compress(const char *filename){assert(filename);FILE *pf=fopen(filename,"rb");assert(pf);unsigned char ch=fgetc(pf);//统计字符出现的次数while (!feof(pf)){_infos[ch]._count++;ch=fgetc(pf);}//以该字符出现的次数构建一颗HuffmanTree.CharInfo invalid; //非法值HuffmanTree<CharInfo> ht(_infos,256,invalid);//生成Huffman编码string code;_CreatHuffmanCode(ht.GetRoot(),code);//_CreatHuffmanCode(ht.GetRoot());//压缩文件fseek(pf,0,SEEK_SET); //回到文件头string compressfile=filename;compressfile += ".compress"; //压缩后的文件名FILE *fin=fopen(compressfile.c_str(),"wb");assert(fin);size_t pos=0; //记录位数unsigned char value=0;ch=fgetc(pf);while (!feof(pf)){string &code=_infos[ch]._code;for (size_t i=0;i<code.size();++i){value <<= 1;if(code[i] == '1')value |= 1;elsevalue |= 0; //do-nothing++pos;if(pos == 8) //满一个字节{fputc(value,fin);value=0;pos=0;}}ch=fgetc(pf);}if(pos) //解决不足8位的情况.{value <<= (8-pos);fputc(value,fin);}//配置文件--便于重建Huffman树string ename=filename;configfilename += ".config";FILE *finconfig=fopen(configfilename.c_str(),"wb");assert(finconfig);string line;char buff[128];for (size_t i=0;i<256;++i){//一行一行的读if (_infos[i]._count){line += _infos[i]._ch;line += ",";line += _itoa(_infos[i]._count,buff,10);line += "\n";//fputs(line.c_str(),finconfig);fwrite(line.c_str(),1,line.size(),finconfig);line.clear();}}fclose(pf);fclose(fin);fclose(finconfig);return compressfile;}string UnCompress(const char *filename){assert(filename);string configfilename=filename;size_t index=configfilename.rfind(".");configfilename=configfilename.substr(0,index); configfilename += ".config";FILE *foutconfig=fopen(configfilename.c_str(),"rb"); assert(foutconfig);string line;//读取配置文件--获取字符出现的次数unsigned char ch=0;while (ReadLine(foutconfig,line)){if(line.empty()){line += '\n';continue;}//读到空行ch=line[0];_infos[ch]._count = atoi(line.substr(2).c_str());line.clear();}//构建Huffman树CharInfo invalid;HuffmanTree<CharInfo> hft(_infos,256,invalid);//根结点的权值也就是字符出现的次数总和HuffmanTreeNode<CharInfo> *root=hft.GetRoot(); Type charcount=root->_weight._count;//解压缩string uncompressfilename=filename;index=uncompressfilename.rfind("."); uncompressfilename=uncompressfilename.substr(0,index); uncompressfilename += ".uncompress";FILE *fin=fopen(uncompressfilename.c_str(),"wb"); assert(fin);//由压缩文件还原文件string compressfilename=filename;FILE *fout=fopen(compressfilename.c_str(),"rb");assert(fout);HuffmanTreeNode<CharInfo> *cur=root;int pos=7;ch=fgetc(fout);while (charcount > 0){while (cur){if(cur->_left == NULL && cur->_right == NULL){//叶子结点fputc(cur->_weight._ch,fin);cur=root;--charcount;if (charcount == 0) //所有的字符都处理完成break;}if (ch & (1 << pos)) //检查字符的每个位cur=cur->_right; //1向右走elsecur=cur->_left; //0向左走--pos;if(pos < 0) //一个字节解压完成{ch=fgetc(fout);pos=7;}}}fclose(foutconfig);fclose(fin);fclose(fout);return uncompressfilename;}//读取一行字符并放在line中bool ReadLine(FILE *fout,string& line){int ch=fgetc(fout);if(ch == EOF)return false;while (ch != EOF && ch != '\n'){line += ch;ch=fgetc(fout);}return true;}protected://递归的方法求HuffmanTreeCodevoid _CreatHuffmanCode(HuffmanTreeNode<CharInfo> *root,string &code) {if(root == NULL)return ;_CreatHuffmanCode(root->_left,code+'0');_CreatHuffmanCode(root->_right,code+'1');if(root->_left == NULL && root->_right == NULL) //叶子结点{_infos[root->_weight._ch]._code=code;}}//非递归求HuffmanTreeCodevoid _CreatHuffmanCode(HuffmanTreeNode<CharInfo> *root){if(root == NULL)return ;_CreatHuffmanCode(root->_left);_CreatHuffmanCode(root->_right);if(root->_left == NULL && root->_right == NULL) //叶子结点{string& code=_infos[root->_weight._ch]._code;HuffmanTreeNode<CharInfo> *cur=root;HuffmanTreeNode<CharInfo> *parent=root->_parent;while (parent){if(parent->_left == cur)code.push_back('0'); //左0elsecode.push_back('1'); //右1cur=parent;parent=cur->_parent;}//编码是从根到叶子结点的,需要逆置reverse(code.begin(),code.end());}}protected:CharInfo _infos[256];};void testFileCompress(){FileCompress fc;cout<<"开始压缩"<<endl;cout<<"压缩用时:";int start=GetTickCount();press("2.png"); //input input.BIG 3.mp3int end=GetTickCount();cout<<end-start<<endl;cout<<"开始解压"<<endl;cout<<"解缩用时:";start=GetTickCount();fc.UnCompress("press"); //press press 3.mp3end=GetTickCount();cout<<end-start<<endl;}void testFileUncompress(){FileCompress fc;cout<<"开始解压"<<endl;cout<<"解缩用时:";int start=GetTickCount();fc.UnCompress("2.png");int end=GetTickCount();cout<<end-start<<endl;}经过测试这个小项目已经可以压缩并还原一些文件了,目前还没有发现什仫大的Bug,如果有童鞋发现请第一时间告诉我哦...。
训练2+用Huffman编码实现文本文件的无损压缩
用Huffman编码实现文件压缩算法设计训练(2)2011-3-21基本要求•目标–独立完成一个中等规模的项目–在程序设计中使用中等复杂度的数据结构•基本要求–自行建立一个测试文件a.txt•测试文件可以仅包含字母和数字,但不能仅有数字•测试文件中不能是单一的字符、空文件等(即不可对测试文件进行投机)–编写程序对测试文件进行压缩,并将压缩结果保存为一个新文件–编写程序对压缩后的新文件进行解压–要求“无损压缩”,即(源文件Æ压缩Æ解压)==(源文件)–要求用一个程序实现压缩和解压,以main 函数参数的形式提供压缩和解压的选项2011-3-21具体实现•基本要求的具体实现要求–扫描文件产生每个字符的使用频率–对每个字符根据使用频率建立最小堆–由最小堆建立Huffman 树–自行建立一个测试文件a.txt–用Huffman 树对测试文件进行压缩,并将压缩文件保存为a.hfm –将Huffman 树存储在a.hfm 的头部–以main 函数参数的形式提供解压的选项,以a.hfm 恢复出a.txt2011-3-21扩展要求•扩展要求–实现Holy Bible, Authorized (King James) Version (圣经,詹姆斯.金版见附件:kjv.rar)的压缩和解压缩–计算由Huffman 树给的压缩算法的压缩比•(压缩比=压缩后的文件大小/压缩前的文件大小)–尝试以下3种压缩方式• a. 扫描整个文件,以每个字符实际出线的频率计算Huffman 数• b. 不扫描整个文件,以英文字符的平均出线频率计算huffman 树• c. 扫描整个文件,以英文单词做为编码对象–提示•由于原文中是区分大小写的,并且要处理标点符号、数字等因此需要对0~255的ASCII 字符重新进行Huffman 编码•不同的Huffman 编码策略可以由main 函数的参数给出(参考字符界面的RAR)2011-3-21完整的作业要求•格式要求:•1.要求提交实验报告和源代码。
Huffman编码在数据压缩中的实际应用案例
Huffman编码在数据压缩中的实际应用案例Huffman编码是一种常用的数据压缩算法,它通过利用字符出现频率的统计信息,将出现频率较高的字符用较短的编码表示,从而实现数据的高效压缩。
本文将介绍Huffman编码在实际应用中的各种案例。
1. 文本文件压缩文本文件是最常见的需要进行压缩的数据类型之一。
Huffman编码可以通过分析文本中出现的字符及其频率,为每个字符生成唯一的编码。
根据字符出现的频率不同,生成的编码长度也不同,使得出现频率较高的字符可以用更短的编码表示,从而实现对文本文件的有效压缩。
例如,一个包含大量英文字符的文本文件,使用Huffman编码可以将每个字符表示为一个较短的二进制序列,从而极大地减少文件大小。
2. 图像压缩图像是另一个常见的需要进行压缩的数据类型。
Huffman编码在图像压缩中的应用主要体现在色彩编码上。
对于彩色图像,Huffman编码可以将不同的颜色值映射为不同的二进制序列,使得出现频率较高的颜色可以用较短的编码表示。
通过使用Huffman编码,可以将图像文件压缩为更小的文件大小,而且在解压缩时能够恢复高质量的图像。
3. 音频压缩音频文件的压缩通常是有损压缩,即通过减少音频数据的冗余和不重要的部分来实现压缩。
Huffman编码可以用于对音频信号进行压缩编码,特别是在语音文件压缩中应用广泛。
通过对语音中的音频信号进行采样和量化,并使用Huffman编码对采样后的数据进行压缩,可以显著减少语音文件的大小。
这在电信领域中被广泛应用于语音通信和存储。
4. 视频压缩类似于音频压缩,视频压缩也是有损压缩的一种形式。
在视频压缩中,Huffman编码常常与其他压缩算法(如离散余弦变换或小波变换)结合使用,以进一步减小文件大小。
Huffman编码可以用于对视频中的图像帧进行编码,从而减少文件大小并提高传输和储存效率。
例如,在MPEG标准中,Huffman编码被用于对DCT变换后的视频图像进行熵编码,以实现高效的视频压缩。
huffman编码译码实现文件的压缩与解压.
数据结构课程设计题目名称:huffman编码与解码实现文件的压缩与解压专业年级:组长:小组成员:指导教师:二〇一二年十二月二十六日目录一、目标任务与问题分析 (2)1.1目标任务 (2)1.2问题分析 (2)二、算法分析 (2)2.1构造huffman树 (2)2.1.1 字符的统计 (2)2.1.2 huffman树节点的设计 (2)2.2构造huffman编码 (3)2.2.1 huffman编码的设计 (3)2.3 压缩文件与解压文件的实现 (3)三、执行效果 (4)3.1界面 (4)3.2每个字符的编码 (4)3.3操作部分 (5)3.4文件效果 (6)四、源程序 (7)五、参考文献 (16)huffman编码与解码实现文件的压缩与解压一、目标任务与问题分析1.1目标任务采用huffman编码思想实现文件的压缩和解压功能,可以将任意文件压缩,压缩后也可以解压出来。
这样即节约了存储空间,也不会破坏文件的完整性。
1.2问题分析本问题首先应该是利用哈夫曼思想,对需要压缩的文件中的个字符进行频率统计,为了能对任意的文件进行处理,应该所有的文件以二进制的方式进行处理,即对文件(不管包含的是字母还是汉字)采取一个个的字节处理,然后根据统计的频率结果构造哈夫曼树,然后对每个字符进行哈夫曼编码,然后逐一对被压缩的文件的每个字符构建的新的哈夫曼编码存入新的文件中即得到的压缩文件。
解压过程则利用相应的哈夫曼树及压缩文件中的二进制码将编码序列译码,对文件进行解压,得到解压文件。
二、算法分析2.1构造huffman树要利用哈夫曼编码对文本文件进行压缩,首先必须知道期字符相应的哈夫曼编码。
为了得到文件中字符的频率,一般的做法是扫描整个文本进行统计,编写程序统计文件中各个字符出现的频率。
由于一个字符的范围在[0-255]之间,即共256个状态,所以可以直接用256个哈夫曼树节点即数组(后面有节点的定义)空间来存储整个文件的信息,节点中包括对应字符信息,其中包括频率。
哈夫曼编码的压缩与解压缩
哈夫曼编码的压缩与解压缩1.引言1.1 概述哈夫曼编码是一种常用的数据压缩算法,它采用了一种变长编码方式,将出现频率高的字符用较短的编码表示,出现频率低的字符用较长的编码表示,以达到压缩数据的目的。
该编码方法由美国数学家大卫·哈夫曼于1952年提出,被广泛应用于各种数据压缩和传输领域。
在传统的固定长度编码中,每个字符都使用相同的位数来表示,因此在表示不同概率出现的字符时,可能会浪费大量的位数。
而哈夫曼编码则是根据字符在文本中出现的频率来确定其对应的编码,使得高频出现的字符用更短的编码表示,低频出现的字符用较长的编码表示。
哈夫曼编码的核心思想是构建一棵哈夫曼树,将出现频率作为权值,频率越高的字符离根节点越近。
通过从叶子节点到根节点的路径确定每个字符的编码,即将左子树标记为0,右子树标记为1。
在对文本进行压缩时,将文本中的字符转换为其对应的哈夫曼编码,即可将原始数据压缩为较短的二进制串。
相比于传统固定长度编码,哈夫曼编码具有显著的优势。
首先,它可以根据文本中字符出现的实际情况进行编码,使得频率高的字符用较短的编码表示,从而大幅度减少了编码后的数据长度。
其次,哈夫曼编码是一种前缀编码,即任何一个字符的编码都不是其他字符编码的前缀,这样在解码时可以直接根据编码找到对应的字符,无需回溯查表,提高了解码效率。
哈夫曼编码的应用广泛,它被用于无损图像压缩、音频压缩、文本压缩等领域。
随着互联网和大数据时代的到来,数据的传输和存储成为重要的问题,如何高效地压缩和解压缩数据成为一个热门的研究方向。
哈夫曼编码作为一种简单而有效的压缩算法,具有广阔的应用前景。
然而,哈夫曼编码也存在一些问题,如编码时需要构建哈夫曼树,需要额外的空间和时间开销,对于小规模数据可能会影响压缩效率。
因此,在实际应用中,需要综合考虑数据规模和应用场景,选择合适的压缩算法。
1.2 文章结构本文主要介绍了哈夫曼编码的压缩与解压缩。
文章分为引言、正文和结论三个部分。
Huffman的应用之文件压缩与解压缩汇总
1).因为有些特殊的字符编码,所以我们统计字符出现的次数的时候应该用的是unsigned char,刚开始我用的文件结束标志是EOF在ASII中它的编码是-1此时已经不可以用EOF来判断是否文件结束了,所以我用了feof这个函数来判断文件是否结束.
template<class T>
struct HuffmanTreeNode
{
T _weight;
HuffmanTreeNode<T> *_left;
HuffmanTreeNode<T> *_right;
HuffmanTreeNode<T> *_parent;
HuffmanTreeNode(const T& w=T())
Huffman的应用之文件压缩与解压缩
最近这段时间一直在学习树的这种数据结构,也接触到了Huffman树以及了解了什仫是Huffman编码,而我们常用的zip压缩也是利用的Huffman编码的特性,那仫是不是可以自己实现一个文件压缩呢?当然可以了.在文件压缩中我实现了Huffman树和建堆Heap的代码,zip压缩的介绍>
{}
HuffmanTree(const T* a,size_t size)
:_root(NULL)
{
_root=_CreatHuffmanTree(a,size);
}
//将未出现的字符过滤出来,不构造堆
HuffmanTree(const T* a,size_t size,const T& invalid)
下面是我举的一个简单的范例,模拟压缩和解压缩的过程,希望有读者有帮助
使用huffman编码压缩与解压缩(python)
使⽤huffman编码压缩与解压缩(python)⼀、huffman 编码1.1 huffman 编码介绍哈夫曼编码(Huffman Coding),⼜称霍夫曼编码,是⼀种编码⽅式,哈夫曼编码是可变字长编码(VLC)的⼀种。
Huffman于1952年提出⼀种编码⽅法,该⽅法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,⼀般就叫做Huffman编码(有时也称为霍夫曼编码)huffman 编码是最优码,也是即时码(证明较为复杂,在此不给出证明)1.2 huffman 编码此处介绍⼆元 huffman 编码给定⼀个字符集合 S={s0,s1,⋯,s q},每个字符的概率为 P={p0,p1,⋯,p q}将字符集合按概率由⼤到⼩重新排列,即使得p i≥p i+1将最末尾的两个字符s q−1和s q合并,记为s′,s′的概率为p′=p q−1+p q如果剩余的字符数不为 1,则回到第 1 步huffman 编码的过程⼤致就上述三步当编码完毕后,会构建出⼀棵码树,每个码字的编码可以从码树中获得举个简单的例⼦,对于字符集合 S={A,B,C},概率为 P=0.5,0.3,0.2将B,C合并,记为BC,p(BC)=p(B)+p(C)=0.3+0.2=0.5然后将A,BC合并,记为ABC,p(ABC)=p(A)+p(BC)=0.5+0.5=1记根节点 ABC 码字为空,从根节点向下遍历,往左⾛码字末尾添0,往右⾛添1,那么 A, B, C 的码字分别为 0, 10, 11,编码表就是 {A:0,B:10,C:11}1.3 huffman 编程实现见后⽂的代码实现1.4 测试⾸先在代码⽬录下新建⼀个newfile.txt,⾥边写⼊ABCDEFG下⾯的代码实现了读取newfile.txt并对其压缩,将结果输出⾄output.enc然后对output.enc进⾏解压缩,将解压缩结果输出⾄output.dec# 读⼊⽂件with open('newfile.txt', 'rb') as fp_in:str_bytes = fp_in.read()# 构建huffman编码fre_dic = bytes_fre(str_bytes)huffman_dic = build(fre_dic)# 对⽂本进⾏编码str_enc, padding = encode(str_bytes, huffman_dic, False)# 输出⾄⽂件 output.encwith open('output.enc', 'wb') as fp_out:fp_out.write(str_enc)# 对编码后的⽂本进⾏解码str_dec = decode(str_enc, huffman_dic, padding, False)# 输出⾄⽂件 output.decwith open('output.dec', 'wb') as fp_out:fp_out.write(str_dec)# 打印huffman字典和填充位print('huffman_dic:', huffman_dic)print('padding:', padding)观察压缩前和压缩后的⽂件,发现经过我们的程序压缩之后,⽂件⼩了很多使⽤ winhex 打开 newfile.txt, output.enc, output.dec 查看对应的⼗六进制数值观察 newfile.txt 和 output.dec 的⼗六进制数值,发现⼀模⼀样,说明我们的压缩和解压并没有问题,程序正确接下来来分析 output.enc ⽂件的内容output.enc 中的数值为 C1 4E 50,转化成⼆进制为 11000001 01001110 01010000Loading [MathJax]/jax/output/HTML-CSS/jax.js我们将中间构造出的编码表打印出来,可以得到编码表字符A B C D E F G编码11000001010011100101以及填充位 padding 的值为 4我们对 newfile.txt 中的字符 ABCDEFG 进⾏编码,结果为 11 000 001 010 011 100 101。
哈夫曼编码使用哈夫曼编码进行数据压缩与解压缩
哈夫曼编码使用哈夫曼编码进行数据压缩与解压缩在信息技术发展的背景下,数据的传输和存储需求越来越大,如何高效地进行数据压缩成为了重要的课题之一。
哈夫曼编码是一种基于信息熵的编码技术,通过构建最优二叉树,实现了数据的高效压缩和解压缩。
在本文中,我们将探讨哈夫曼编码的原理和应用。
一、哈夫曼编码的原理哈夫曼编码是一种变长编码,它根据字符出现的频率构建一棵最优二叉树,频率较高的字符被赋予较短的编码,频率较低的字符则被赋予较长的编码。
这种编码方式具有无重复前缀码性质,即任意字符的编码都不是其他字符编码的前缀。
这样一来,在解码时就能够准确还原原始数据。
具体实现过程如下:1. 统计字符频率:对待编码的数据进行字符频率统计,得到每个字符出现的次数。
2. 构建哈夫曼树:根据字符频率构建一棵哈夫曼树。
树的每个节点表示一个字符,并且字符的频率决定节点的权重。
构建过程中,每次选择权重最小的两个节点合并形成新的节点,直到所有节点合并为一棵树。
3. 分配编码:从根节点出发,对哈夫曼树的每个子树进行遍历,左子树路径上追加0,右子树路径上追加1,直到到达叶节点。
这样,每个字符都能够找到对应的编码。
4. 进行数据压缩:根据字符的编码,将原始数据进行编码替换,形成压缩后的数据。
编码后的数据长度会变短,达到了数据压缩的目的。
二、哈夫曼编码的应用哈夫曼编码在数据压缩领域有着广泛的应用。
其中,最常见的应用场景是在无损压缩算法中。
通过哈夫曼编码,能够将原始数据进行高效压缩,并在解压缩时准确还原数据,但并不损失任何信息。
此外,哈夫曼编码还经常用于文件压缩、图像压缩和音频压缩等领域。
在文件压缩中,能够将大文件转换为更小的压缩文件,方便传输和存储。
在图像压缩中,通过对图像数据进行编码,能够减小图像文件的大小,提高传输效率。
在音频压缩中,通过压缩音频数据,减小文件大小,同时保持音频质量,实现高质量的音频传输。
三、哈夫曼编码的优缺点1. 优点:哈夫曼编码是一种高效的数据压缩技术,可以大幅度减小数据的存储和传输空间。
用Huffman编码进行文件压缩的方法
用Huffman编码进行文件压缩的方法
潘玮华
【期刊名称】《电脑知识与技术》
【年(卷),期】2010(006)007
【摘要】介绍了使用Huffman编码进行文件压缩的思路和压缩的方法.详细阐述了该方法所用类的设计和压缩、解压的具体设计方法,并给出使用C++语言描述的完整的程序.
【总页数】4页(P1714-1717)
【作者】潘玮华
【作者单位】南京师范大学计算机科学与技术学院,江苏,南京,210046
【正文语种】中文
【中图分类】TP37
【相关文献】
1.用Huffman编码对文件进行压缩的C语言实现 [J], 路炜;门玉梅;李建俊
2.基于Huffman编码的XML文件压缩存储算法研究与实现 [J], 周伟
3.利用Winrar进行文件压缩(解压缩)的两点改进 [J], 李伟春
4.运用Huffman编码进行数据压缩的新算法 [J], 何昭青
5.基于Huffman编码的XML文件压缩存储算法研究与实现 [J], 周伟
因版权原因,仅展示原文概要,查看原文内容请购买。
基于哈夫曼编码实现文本文件的压缩和解压缩实验报告模板
本科学生设计性实验报告软件工程技能实践Ⅰ项目组长陈启学号_*******专业软件工程班级_15软件7 班成员陈启杨林昌邓志远万胜实验项目名称_指导教师及职称__讲师__开课学期2015 至2016 学年第二学期一、实验设计方案1、实验任务与目的(简单介绍实验内容,说明实验任务和目的)1.1实验内容根据ascii码文件中各ascii字符出现的频率情况创建Haffman树,再将各字符对应的哈夫曼编码写入文件中,实现文件压缩。
对于给定的一组字符,可以根据其权值进行哈夫曼编码,并能输出对应的哈夫曼树和哈夫曼编码;实现哈夫曼解码。
能够分析文件,统计文件中出现的字符,再对文件进行编码,实现文件的压缩和解压缩,能够对于文件的压缩,比例进行统计,能够打印文件。
分析与设计哈夫曼树的存储结构,实现哈夫曼算法以及编码与译码基本功能,并对任意文本文件利用哈夫曼编码进行压缩得到压缩文件,然后进行解压缩得到解压文件。
1.2实验任务和目的1.2.1了解文件的概念。
1.2.2掌握线性链表的插入、删除等算法。
1.3.3掌握Huffman树的概念及构造方法。
1.4.4掌握二叉树的存储结构及遍历算法。
1.5.5利用Huffman树及Huffman编码,掌握实现文件压缩的一般原理。
2、实验思路(详细描述解决问题的整体思路、涉及的算法思想及数据结构等)2.1整体思路2.2涉及的算法思想及数据结构:2.2.1输入要压缩的文件首先运行的时候,用户主界面上有菜单提示该如何使用软件,根据菜单提示选择所要执行的项,依次进行,因为各个环节之间有先后顺序。
第一步为输入压缩软件的名称,由键盘输入文件路径和文件名称,读入字符数组中,打开该文件,按照提示进行压缩。
若打不开,则继续输入。
2.2.2读文件并计算字符频率文件将信息存放在字符数组中;计算每个字符出现的次数,申请一个结构体数组空间,用读取的字符减去字符结束符作为下标记录字符的频率。
2.2.3根据字符的频率,利用Huffman编码思想创建Huffman树将所记录的字符的频率作为权值来创建Huffman树,依次选择权值最小的两个字符作为左右孩子,其和作为父结点的权值,依次进行下去,直到所有的字符结点都成为叶子结点。
用哈夫曼编码C语言实现文件压缩-参考模板
《用哈夫曼编码实现文件压缩》实验报告课程名称数据结构B实验学期2012 至2013 学年第一学期学生所在系部计算机学院年级2011 专业班级信管B111学生姓名学号任课教师兰芸实验成绩用哈夫曼编码实现文件压缩1、了解文件的概念。
2、掌握线性链表的插入、删除等算法。
3、掌握Huffman树的概念及构造方法。
4、掌握二叉树的存储结构及遍历算法。
5、利用Huffman树及Huffman编码,掌握实现文件压缩的一般原理。
微型计算机、Windows 系列操作系统、Visual C++6.0软件根据ascii码文件中各ascii字符出现的频率情况创建Haffman树,再将各字符对应的哈夫曼编码写入文件中,实现文件压缩。
(1)构造Hufffman树的方法—Hufffman算法构造Huffman树步骤:I.根据给定的n个权值{w1,w2,……wn},构造n棵只有根结点的二叉树,令起权值为wj。
II.在森林中选取两棵根结点权值最小的树作左右子树,构造一棵新的二叉树,置新二叉树根结点权值为其左右子树根结点权值之和。
III.在森林中删除这两棵树,同时将新得到的二叉树加入森林中。
IV.重复上述两步,直到只含一棵树为止,这棵树即哈夫曼树。
(2)Huffman编码:数据通信用的二进制编码思想:根据字符出现频率编码,使电文总长最短编码:根据字符出现频率构造Huffman树,然后将树中结点引向其左孩子的分支标“0”,引向其右孩子的分支标“1”;每个字符的编码即为从根到每个叶子的路径上得到的0、1序列。
(3) 解压根据存放在文件中的编码表和文件压缩后的编码,进行一对一的翻译过程。
压缩的代码#include <stdio.h>#include <string.h>#include <stdlib.h>#include <conio.h>struct head{unsigned char b; /*the charactor*/long count; /*the frequency*/long parent,lch,rch; /*make a tree*/char bits[256]; /*the haffuman code*/}header[512],tmp;void yasuo() /*压缩*/{char filename[255],outputfile[255],buf[512];unsigned char c; char wenjianming[255];long i,j,m,n,f;long min1,pt1,flength;FILE *ifp,*ofp;printf("输入文件地址及文件名:");gets(filename);ifp=fopen(filename,"rb"); /*打开源文件*/while(ifp==NULL){ printf("打开文件出错\n");printf("重新输入文件地址及文件名");gets(filename);ifp=fopen(filename,"rb");}printf("输入压缩后的文件地址和文件名及后缀:");gets(wenjianming);ofp=fopen(wenjianming,"wb"); /*创建并打开目的文件*/ while(ofp==NULL){printf("重新输入压缩后的文件地址和文件名及后缀:");ofp=fopen(wenjianming,"wb");}flength=0;while(!feof(ifp)) /*读取ifp文件*/{fread(&c,1,1,ifp); /*按位读取*/header[c].count++;flength++;}flength-1;header[c].count-1; /*读取文件结束*/for(i=0;i<512;i++) /*构造哈弗曼树*/{if(header[i].count!=0)header[i].b=(unsigned char)i;elseheader[i].b=0;header[i].parent=-1;header[i].lch=header[i].rch=-1;}for(i=0;i<256;i++){for(j=i+1;j<256;j++){if(header[i].count<header[j].count){tmp=header[i];header[i]=header[j];header[j]=tmp;}}}for(i=0;i<256;i++)if(header[i].count==0)break;n=i;m=2*n-1;for(i=n;i<m;i++){min1=999999999;for(j=0;j<i;j++){if(header[j].parent!=-1)continue;if(min1>header[j].count){pt1=j;min1=header[j].count;continue;}}header[i].count=header[pt1].count;header[pt1].parent=i;header[i].lch=pt1;min1=999999999;for(j=0;j<i;j++){if(header[j].parent!=-1)continue;if(min1>header[j].count){pt1=j;min1=header[j].count;continue;}}header[i].count+=header[pt1].count;header[i].rch=pt1;header[pt1].parent=i;}for(i=0;i<n;i++){f=i;header[i].bits[0]=0;while(header[f].parent!=-1){j=f;f=header[f].parent;if(header[f].lch==j){j=strlen(header[i].bits);memmove(header[i].bits+1,header[i].bits,j+1);header[i].bits[0]='0';}else{j=strlen(header[i].bits);memmove(header[i].bits+1,header[i].bits,j+1);header[i].bits[0]='1';}}} /*哈弗曼构造结束*/fseek(ifp,0,SEEK_SET); /*把文件指针指向文件的开头*/ fwrite(&flength,sizeof(int),1,ofp); //把哈弗曼代码写入ofp文件fseek(ofp,8,SEEK_SET);buf[0]=0;f=0;pt1=8;while(!feof(ifp)){c=fgetc(ifp); //从流中读取一个字符,并增加文件指针的位置f++;for(i=0;i<n;i++){if(c==header[i].b) break;}strcat(buf,header[i].bits); //把header[i].bits所指字符串添加到buf结尾处j=strlen(buf); //计算字符串buf的长度c=0;while(j>=8){for(i=0;i<8;i++){if(buf[i]=='1') c=(c<<1)|1;else c=c<<1;}fwrite(&c,1,1,ofp);pt1++;strcpy(buf,buf+8);j=strlen(buf);}if(f==flength)break;}if(j>0){strcat(buf,"00000000");for(i=0;i<8;i++){if(buf[i]=='1') c=(c<<1)|1;else c=c<<1;}fwrite(&c,1,1,ofp);pt1++;}fseek(ofp,4,SEEK_SET); /*fseek 用于二进制方式打开的文件,移动文件读写指针位置.第一个是文件流,第3个是指针零点位置,第2个是把指针移动到的地点. */ fwrite(&pt1,sizeof(long),1,ofp); /*是要输出数据的地址,每次写入的位数,数据项的个数,目标文件地址*/fseek(ofp,pt1,SEEK_SET);fwrite(&n,sizeof(long),1,ofp);for(i=0;i<n;i++){fwrite(&(header[i].b),1,1,ofp);c=strlen(header[i].bits);fwrite(&c,1,1,ofp);j=strlen(header[i].bits);if(j%8!=0) /*按八位读取*/{for(f=j%8;f<8;f++)strcat(header[i].bits,"0");}while(header[i].bits[0]!=0){c=0;for(j=0;j<8;j++){if(header[i].bits[j]=='1') c=(c<<1)|1;else c=c<<1;}strcpy(header[i].bits,header[i].bits+8); /*把从header[i].bits+8地址开始且含有NULL结束符的字符串赋值到以header[i].bits开始的地址空间*/fwrite(&c,1,1,ofp);}}fclose(ifp);fclose(ofp);printf("压缩成功\n");}void main() /*主函数*/{printf("输入a开始压缩\n");printf("输入b结束压缩\n");while(1){char c;c=getch();if(c=='a')yasuo();else{ if(c=='b')return;}}}压缩的图解解压的代码#include <stdio.h>#include <string.h>#include <stdlib.h>#include <conio.h>struct head{unsigned char b; /*the charactor*/long count; /*the frequency*/long parent,lch,rch; /*make a tree*/char bits[256]; /*the haffuman code*/}header[512],tmp;void jieya() /*解压*/ {char filename[255],outputfile[255],buf[255],bx[255];unsigned char c; char wenjianming[255];long i,j,m,n,f,p,l;long flength;FILE *ifp,*ofp;printf("要解压的文件:");gets(filename);ifp=fopen(filename,"rb"); /*打开源文件*/while(ifp==NULL){ printf("打开文件出错\n");printf("重新输入文件地址及文件名");gets(filename);ifp=fopen(filename,"rb");}printf("输入解压后的文件地址和文件名及后缀:");gets(wenjianming);ofp=fopen(wenjianming,"wb"); /*创建并打开目的文件*/ while(ofp==NULL){ofp=fopen("d:\\123\\解压的文件.txt","wb");}fread(&flength,sizeof(long),1,ifp);fread(&f,sizeof(long),1,ifp);fseek(ifp,f,SEEK_SET);fread(&n,sizeof(long),1,ifp);for(i=0;i<n;i++){fread(&header[i].b,1,1,ifp);fread(&c,1,1,ifp);p=(long)c;header[i].count=p;header[i].bits[0]=0;if(p%8>0) m=p/8+1;else m=p/8;for(j=0;j<m;j++){fread(&c,1,1,ifp);f=c;itoa(f,buf,2);f=strlen(buf);for(l=8;l>f;l--){strcat(header[i].bits,"0");}strcat(header[i].bits,buf);}header[i].bits[p]=0;}for(i=0;i<n;i++){for(j=i+1;j<n;j++){if(strlen(header[i].bits)>strlen(header[j].bits)){tmp=header[i];header[i]=header[j];header[j]=tmp;}}}p=strlen(header[n-1].bits);fseek(ifp,8,SEEK_SET);m=0;bx[0]=0;while(1){while(strlen(bx)<(unsigned int)p){fread(&c,1,1,ifp);f=c;itoa(f,buf,2);f=strlen(buf);for(l=8;l>f;l--){strcat(bx,"0");}strcat(bx,buf);}for(i=0;i<n;i++){if(memcmp(header[i].bits,bx,header[i].count)==0) break;}strcpy(bx,bx+header[i].count);c=header[i].b;fwrite(&c,1,1,ofp);m++;if(m==flength) break;}fclose(ifp);fclose(ofp);printf("解压成功\n");return;}void main() /*主函数*/{printf("输入a开始解压\n");printf("输入b结束解压\n");while(1){char c;c=getch();if(c=='a')jieya();else{ if(c=='b')return;}}}七、测试结果及分析:压缩前的文件夹中的内容压缩后的文件夹中的内容解压后文件夹中的内容八、教师评语:---精心整理,希望对您有所帮助。
数据结构实验报告利用Huffman编码对文件进行压缩解压
《数据结构》实验报告利用Huffman编码对文件进行压缩解压学生:XXX学号:XXXXXXXX联系:XXXXXX@(一)基本信息1.实验题目利用Huffman编码对文件进行压缩解压2.完成人(姓名、学号)姓名:XXX 学号:XXXXXXXX3.报告日期2007年12月12日星期二(二)实习内容简要描述1.实习目标学会对树的基本操作学会对文件进行操作利用Huffman编码对文件压缩解压2.实习要求实现最小堆模板类利用最小堆构建Huffman树实现Huffman编码和解码根据用户从键盘输入的报文文本,输出各字符的Huffman编码以及报文的编码根据用户从键盘输入一串报文文本,输出各字符的Huffman编码输出报文的Huffman编码及长度根据输入的Huffman编码,解码输出利用Huffman编码和解码对二进制文件的压缩和解压(三)报告主要内容1.设计思路开发环境:Microsoft Visual C++ 2005设计思路:1.设计Pack类储存字符的权值2.设计MinHeap模板类构建最小堆3.设计ExtBinTree模板类为带权二叉树4.设计Compress模板类以实现文件的压缩解压2.主要数据结构1.MinHeap.h: 头文件,包含MinHeap模板类的类界面以及定义;2.HuffmanTree.h:头文件,包含ExtBinTree模板类以及Compress模板类的类的的类界面以及定义3.main.cpp:调用上述头文件实现相关操作3.主要代码结构主要代码结构为见附件中各文件的代码注释4.主要代码段分析主要代码段分析,见附件中的代码注释(四)实习结果1.基本数据源程序代码行数:约800行完成该实习投入的时间:二十四小时(不包括写实验报告的时间)与其他同学讨论交流情况:感谢刘畅同学对程序的测试2.测试数据设计1.对屏幕输入字符进行Huffman编码2.根据Huffman树非唯一性,虽然和课件上有些许不同,但是还是正确的3.输入字符串:CASTCASTSATATATASA4.输出编码:A:0 C:110 S:111 T:105.输入霍夫曼编码:01110101101106.输出译码:ASATCC7.8.对”实验05.PPT”的压缩操作9.使用0秒(不足一秒按0秒计算),压缩率为56.1755%10.对”实验05.ppt.hfm”(即刚才生成的压缩文件)的解压操作11.使用0秒(不足一秒按0秒计算),解压后文件无异常12.对一个18M的EXE安装包前后进行压缩和解压操作,分别用时10秒和9秒3.测试结果分析A)程序运行的系统资源配置操作系统:Microsoft Windows XP Professional SP2CPU: AMD Athlon 3600+ 2.0GRAM: 1024M DDRII开发环境:Microsoft Visual C++ 2005B)对TXT文档进行压缩和解压后,通过WinMerge检验和原文件无差异C)对MP3和EXE文件压缩和解压后仍能正常使用D)对于中文名字和带有空格的路径均能正确无误识别E)文件名只能小于16个字符(包括后缀名),否则解压会出错(只预留了16个字节用于储存文件名)F)相对于不用文件块读写的程序,效率提高了三倍以上G)具有动态进度条,可以显示当前压缩和解压的进度百分比(当然消耗了一些系统资源)H)出错处理不够充分,特别是cin部分,如果误输入可能会造成死循环(五)实习体会1.实习过程中遇到问题及解决过程A)一开始时候的程序运行很慢,,压缩一个4M左右的文件需要七八秒,后来改用文件块缓存字节来读写后,压缩一个4M的文件只需要两秒左右的时间.本来是只想写一个进度条而已的,后来发现如果只读一个字节就判断一次进度条的话会很消耗系统资源,后来干脆麻烦点用文件块来缓存.不过至于一次缓存多少字节才能达到最好的效果还未知,现在设置的是一次缓存40KB 的数据B)本来一个一个字节读的时候对最后一个字节的操作基本没费什么劲,但是在文件块读写的时候就不是那么清晰明了了,后来经过仔细Debug,才找到错误的所在.许多问题都是这样C)对于中文名和带空格路径,用C++的fstream就不支持,但是C中的FILE*就支持,不知道为什么.还有C++中的fstream的成员函数read返回值很奇怪,不知道如何获取成功读入的项数.改用C中的FILE*文件指针后就解决掉了D)由于这次实验的各个步骤是一环套一环的,在哪里出错很难找得出来,所以这次实验调试消耗的时间特别多.最郁闷的一次错误是发现在取得字符C的第N位函数中,居然把0x40写成了0x30.有时候文件解压出来不对,但是又不清楚是压缩时候错了,还是解压时候错了,然后就要两个函数都要检查一遍.2. 实习体会和收获这次实验最大的特点在于难找错,很锻炼自己的Debug能力(六)自评成绩分数:90 //功能做得较齐全,程序的效率也不错(七)参考文献MSDN还有某网站上树的遍历算法(八)源程序见同一文件夹内.。
实验2 Huffman编码对英文文本的压缩和解压缩
《信息论与编码》实验报告班级:学号:姓名:完成时间:2011年6月2日实验2 Huffman编码对英文文本的压缩和解压缩一、实验内容根据信源压缩编码——Huffman编码的原理,制作对英文文本进行压缩和解压缩的软件。
要求软件有简单的用户界面,软件能够对运行的状态生成报告,分别是:字符频率统计报告、编码报告、压缩程度信息报告、码表存储空间报告。
二、实验环境1.计算机2.Windows 2000 或以上3.Microsoft Office 2000 或以上4.VC++ 6.05.MSDN6.0三、实验目的1.掌握Huffman编码的原理2.掌握VC开发环境的使用(尤其是程序调试技巧)3.掌握C语言编程(尤其是位运算和文件的操作)4.掌握数据结构的内容:链表、顺序表、堆栈、最优二叉树5.掌握结构化程序分析和开发的软件工程原理四、实验要求1.提前预习实验,认真阅读实验原理。
2.认真高效的完成实验,实验过程中服从实验室管理人员以及实验指导老师的管理。
3.认真填写实验报告。
要求有实验问题、实验原理、Matlab的源程序以及实验结果(实验内容中)。
4.每个同学必须独立完成实验(不能抄袭,否则两人均为零分),实验成绩是该门课程成绩的主要依据。
五、实验原理1.压缩/解压缩流程压缩流程:解压缩流程:2.Huffman编码算法(略)3.文件操作和位运算(略)六、Huffman 算法的8种不同实现方式1. huffman_a 使用链表结构生成Huffman树的算法,这是最基本的实现方法,效率最低。
2. huffman_b 使用《数据结构》(严蔚敏,吴伟民,1997,C语言版)中给出的算法,将二叉树存放在连续空间里(静态链表),空间的每个结点内仍有左子树、右子树、双亲等指针。
3. huffman_c 使用Canonical Huffman编码,同时对huffman_b的存储结构进行改造,将二叉树存放在连续空间tree里,空间的每个结点类型都和结点权值的数据类型相同,空间大小为2*num,tree[0]未用,tree[1..num]是每个元素的权值,生成Huffman后,tree[1..2*num-1]中是双亲结点索引。
利用改进的哈夫曼编码实现文件的压缩与解压
L u Bi n g , L i u Xi n g h a i
( Z h e n g z h o u I n s t i t u t e o f L i g h t I n d u s t r y , C o mp u t e r a n d C o m mu n i c a t i o n E n g i n e e i r n g I n s t i t u t e , Z h e n g z h o u 4 5 0 0 0 2 , C h i n a )
p o s e d . Ac c o r d i n g t o t h e c l a s s i c Hu f ma n a l g o it r h m, u s i n g t h e h e a p s o r t t h o u g h t t o b u i l d t h e Hu f ma n t r e e a n d t h e Hu f - ma n c o d i n g ,t h i s me t h o d c a n r e d u c e t h e me mo r y r e a d a n d wr i t e t i me s , i mp r o v i n g t h e s y s t e m r e s p o n s e t i me . T h r o u g h t h e s e c o n d ma p p i n g , e a c h 8 e n c o d e d il f e b i n a y r i s c o n v e te r d i n t o a c o r r e s p o n d i n g c h a r a c t e r , i mp r o v e t h e c o mp r e s s i o n r a t i o o f i f l e s a n d e n s u r e t h e s e c u i r t y a n d c o n i f d e n t i a l i t y o f t h e r e s u l t i n g c o mp r e s s e d i f l e . F i n a l l y , t h r e e t e x t f i l e s c o mp r e s s i o n t e s t o n he t i mp r o v e d Hu f f ma n a l g o r i t h m, e x p e i r me n t s s h o w t h a t t h e i mp r o v e d a l g o r i t h m, t h e c o mp r e s s i o n r a t i o i s s l i g h t l y b e t —
文件的压缩与解压huffman算法功能实现
文件的压缩与解压──huffman算法功能实现摘要:压缩的实质是数字变换,在多媒体信息中包含大量冗余的信息,把这些余冗的信息去掉,就是实现了压缩;解压是由于计算机处理的信息是以二进制数的形式表示的,因此压缩软件就是把二进制信息中相同的字符串以特殊字符标记来达到压缩的目的。
关键词:压缩;解压缩;需求分析;概要设计;详细设计;测试Abstract:Compression is the essence of digital transformation, contains a large amount of redundant information in the multimedia information, the residual redundancy information, is to implement the compression; Decompression is due to the computer processing of information in the form of a binary number, so the compression software is binary information in the same string tag as special characters to achieve the purpose of compression.Key words:Compression; The decompression; Demand analysis; The profile design; The detailed design; Test;1 需求分析解决整个项目系统的“做什么”的问题。
在这里,对于开发技术并没有涉及,而主要是通过建立模型的方式来描述用户的需求,为客户、用户、开发方等不同参与方提供一个交流的渠道。
随着科学技术的进步,信息技术越来越广泛地应用到社会的各个行业和领域,互联网深刻地改变着人们的生活方式,推动着人类文明的进步。
郝夫曼编码实现的文件压缩和解压.
重庆大学实验报告实验题目:学院:专业班级:计算机科学与技术五班六班年级:姓名:学号:年月指导教师:重庆大学教务处制实验项目指导教师评定成绩表指导教师评定成绩:指导教师签名:年月日实验项目指导教师评定成绩表指导教师评定成绩:指导教师签名:实验项目指导教师评定成绩表指导教师评定成绩:指导教师签名:重庆大学本科学生实验项目任务书实验报告正文一.需求分析1.有时候我们需要用到将文件进行压缩,以节省空间,是信息得到更更好的存储,特别是一些现在不用到,可以将其进行压缩而以后需要用的时候再解压;2.郝夫曼编码刚好可以实现我们的这一需要,利用郝夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本;3.郝夫曼编码的原理比较简单:对于计算机存储文件,它是按照二进制,对应于每个字符的ASCII值,以01序列存储,但是,如果我们把某一个文件中不同字符出现的频率进行统计,然后按照权值排好序,构建一棵郝夫曼树,将权值较大的用较短的01序列编码,相反,将权值较小的用较长的01序列编码,这样就可以达到整个编码长度的最优,这样,用来存储每个字符的01序列在很大程度上比原来计算机的一般存储方式下的01序列要短,这样就达到了压缩的目的;或者可以看作是一个加密解密的过程,因为计算机存储是按照二进制进行的,但是我们是看不到底层的01序列的,它会把01序列转化为对应字符的ASCII值,然后存储该字符;4.郝夫曼压缩实现方法主要在郝夫曼树的构建,压缩解压函数的实现,所以比较实用,易于实现。
二.系统设计1.我们首先要有一个控制面板,实现对程序的调试功能的操作:因此,在VS2010下建立一个Qt项目,通过对控制面板上的信息响应函数的实现以达到压缩解压的母的,而信息响应函数的内部又去调用我们事先写好的郝夫曼树类中的郝夫曼树的构建函数和压缩解压函数,所以,我们又在VS环境中声明并定义一些相关操作的函数,主要有compress(压缩函数),decompress(解压函数),select(选择函数),change(对调函数),getweight(得到权重函数),return(返回参与编码的字符数)以及reinit(重初始化函数(重清空));在QT中,我们有如下的函数及功能实现:Widget(对信息响应的函数进行初始化),open_source (打开要被压缩的目标文件) open_des(找出解压的文件另存的地址)dealstr(修改地址)des_info(解压后的文件长度)source_info (要压缩的文件的长度) Go(进行压缩/解压操作)2.具体类图如下:郝夫曼树类继承基类的一些树的基本信息,以实现接口连接;QT中Widget类中的函数(与界面信息直接相连的)来调用郝夫曼树中已经写好的压缩解压函数,具体的关系流程如下图:3.再来看看我们的界面:(1)我们设计了encode和decode两个按钮是方便对压缩还是解压的选择,因为在程序内部我们的Go按钮是通过识别两个按钮传进来的信息进行相对应的操作的;(2)在界面上,我们可以看到当点击压缩并打开路径文件时,下面的路径框里会自动显示所选的文件详细路径,对于解压的目的文件(或称为另存为)路径也会在选中之后显示出来,这样就方便我们去查找源文件和压缩文件了;(3)下面的undeocded和deocded information 就是通过我们在选中文件和点击Go操作时进行的,并将这些结果显示到屏幕上,主要包括:源文件字节长度,压缩后的头文件字节长度,平均字节长度,压缩后的文件字节长度以及压缩率。
霍夫曼对英文文档编码解码
霍夫曼树编码一、问题描述对带压缩文本进行扫描,统计文中各符号出现的次数,利用二叉堆构造霍夫曼编码树,并将霍夫曼编码进行压缩、发送、解压。
二、基本要求1.压缩过程(1)扫描待压缩文本并统计文中各符号出现的频率/次数(使用一大小为256的整形数组)。
(2)找出有效符号的个数,比如n。
动态创建一大小为2n-1的结构数组,用于构建霍夫曼编码树。
(3)霍夫曼编码树的创建需要在数组中不断地找出频率属性最小者和次小者。
使用二叉堆来实现。
(4)遍历霍夫曼编码树,计算出各符号的码字。
(5)再次扫描文本,使用霍夫曼编码生成新的压缩文件。
文件内容构成:压缩内容字节数+最后一字节有效位数+符号频率数组(256)+压缩内容。
2.解压缩过程(1)打开已压缩文件,读出符号频率数组内容,构建解码用霍夫曼编码树。
(2)从文件中顺序读出二进制码位,利用编码树进行解码。
一个符号的解码过程也是一次从根节点到叶节点的遍历过程。
三、测试数据扫描word.txt文本,内容如下:i am so clever!guad asdfgiugfyiuwqb asffgyicbiafgiyqyrfg acbiyqwgf cbqu,cbwuqifgrq.cwuqvgqgbcaeecbyiaydgcyaib auifgyiuagf四、算法思想本次实习是在Huffman编码及其解码基础上,对编码内容进行压缩,接收端进行解压解码。
所以Huffman建树、void Compress(int codewords[],int code_len,int weight[],int t)压缩函数以及void Decompress(int w[],int wt[])解压函数是实现问题要求的主要函数。
1.huffman算法(1)以权值分别W1,W2,...Wn的n个结点,构成n棵二叉树F={T1,T2...Tn},其中每棵二叉树只有一个权值为Wi的根结点。
(2)在F中选取两棵根结点权值最小的树作为左右子树构造一棵新二叉树,且新二叉树根结点权值为左右子树权值之和。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
数据结构课程设计题目名称:huffman编码与解码实现文件的压缩与解压专业年级:组长:小组成员:指导教师:二〇一二年十二月二十六日目录一、目标任务与问题分析 (2)1.1目标任务 (2)1.2问题分析 (2)二、算法分析 (2)2.1构造huffman树 (2)2.1.1 字符的统计 (2)2.1.2 huffman树节点的设计 (2)2.2构造huffman编码 (3)2.2.1 huffman编码的设计 (3)2.3 压缩文件与解压文件的实现 (3)三、执行效果 (4)3.1界面 (4)3.2每个字符的编码 (4)3.3操作部分 (5)3.4文件效果 (6)四、源程序 (7)五、参考文献 (16)huffman编码与解码实现文件的压缩与解压一、目标任务与问题分析1.1目标任务采用huffman编码思想实现文件的压缩和解压功能,可以将任意文件压缩,压缩后也可以解压出来。
这样即节约了存储空间,也不会破坏文件的完整性。
1.2问题分析本问题首先应该是利用哈夫曼思想,对需要压缩的文件中的个字符进行频率统计,为了能对任意的文件进行处理,应该所有的文件以二进制的方式进行处理,即对文件(不管包含的是字母还是汉字)采取一个个的字节处理,然后根据统计的频率结果构造哈夫曼树,然后对每个字符进行哈夫曼编码,然后逐一对被压缩的文件的每个字符构建的新的哈夫曼编码存入新的文件中即得到的压缩文件。
解压过程则利用相应的哈夫曼树及压缩文件中的二进制码将编码序列译码,对文件进行解压,得到解压文件。
二、算法分析2.1构造huffman树要利用哈夫曼编码对文本文件进行压缩,首先必须知道期字符相应的哈夫曼编码。
为了得到文件中字符的频率,一般的做法是扫描整个文本进行统计,编写程序统计文件中各个字符出现的频率。
由于一个字符的范围在[0-255]之间,即共256个状态,所以可以直接用256个哈夫曼树节点即数组(后面有节点的定义)空间来存储整个文件的信息,节点中包括对应字符信息,其中包括频率。
2.1.1 字符的统计用结构体huffchar来存放文件字符的信息。
其中有文件中不同字符出现的种类Count、字符data。
struct huffchar{//存放读入字符的类;int Count;//字符出现的个数;char data;//字符;};函数实现:bool char_judge(char c)//判断字符出现的函数;void char_add(char c)//添加新出现的字符;void read_file_count() //文件的读取2.1.2 huffman树节点的设计用结构体huff_tree来存储结点信息,其中有成员频率weight、父亲节点parent、左儿子节点lchild、右儿子节点rchild。
struct huff_tree{//huffman树结点定义;int parent;int lchild;int rchild;int weight;};函数实现:void creathuffman() //构造huffman树的函数2.2构造huffman编码2.2.1 huffman编码的设计用结构体huffcode来存储每个字符的编码。
其中有编码数组bits、起始编码start、频数count、编码对应的字符c。
struct huffcode{//结构体string bits[100];//存放解码;int start;//int count;//频数string c;//存放字符;};函数实现:void huffmancode()//编码函数2.3 压缩文件与解压文件的实现将压缩的文件根据huffman树进行编码,存入新的文件(huffman1.txt)中,将huffman.txt 按照huffman编码对应的字符解压回来,但是这样的文件是压缩不了的,当时用了一个30kb 的文件压缩后竟然成了119kb,导致这样的问题是因为一个字符对应几个二进制数字,然而一个二进制文字也是占一个字节,这就导致了压缩后的文件变大。
处理的方法将huffman1.txt文件中的二进制编码7位7位的存成一个ascII值存入新的文件,这样就实现了真正打压缩。
解压的时候将文件中的ascII值重新弄成二进制,不够7位的前边补0,例如ascII值为99的二进制位100011这是6位的ascII码所以再前边补一个0那么99的二进制就变成0100011。
接下来就利用huffman编码将这个文件重新译码过来。
函数实现:void code_huffman_file()//编码后的二进制码存入文件void code_file_out()//将编码过的文件恢复;void evaluating()//比较文件压缩的比例void change()//将二进制编码变成ascII码void yichu()//将ascII翻译成二进制码恢复文件三、执行效果本算法有一个初始文件为huffman.txt。
为一篇小说,大小为32KB3.1界面3.2每个字符的编码3.3操作部分3.4文件效果huffman为初始文件大小为30KB,huffman1为二进制编码文件大小为130KB,huffman2文件为解压后的文件大小为30KB,huffman3.为真正压缩后的文件大小为19KB,huffman 为huffman3文件解压后的文件大小为30KB,与huffman文件内容相同。
标记的文件就是压缩后的huffman3文件。
四、源程序:#include <iostream>#include <fstream>#include <string>#include <iomanip>#include <cstdio>#include <algorithm>#include <queue>using namespace std;string remfile[3100000];//存放原文件字符的数组;char strstr[1500000];int remcount=0;//记录元素个数;float bitecount=0;//记录二进制码的个数;/****************************************************************/ struct huffchar{//存放读入字符的类;int Count;//字符出现的个数;char data;//字符;};int Count=1;//记录huff数组中字符实际出现的个数;huffchar huff[1000];//类的对象;/****************************************************************//*文件读入部分和统计字符出现的频率*/bool char_judge(char c)//判断字符出现的函数;{for(int i=1;i<=Count;i++)if(huff[i].data==c){huff[i].Count++;return true;}//如果出现过,出现的频数加1;return false;}void char_add(char c)//添加新出现的字符;{huff[Count].data=c;huff[Count++].Count++;//个数增加,}//文件的读取void read_file_count(){char c;ifstream infile;infile.open("huffman.txt");//打开huffman.txt文件;if(!infile)//检查文件是否打开。
{cerr<<"不能打开huffman.txt文件";//输出文件未打开的标志。
exit(0);}cout<<"读入的文件中的内容为:"<<endl;while((c=infile.get())!=EOF){remfile[++remcount]=c;if(!char_judge(c))char_add(c);}cout<<endl;}/******************文件读入和统计字符出现频率部分结束**************/ /******************************************************************//******************构造huffman树程序部分***************************/ struct huff_tree{//huffman树结点定义;int parent;int lchild;int rchild;int weight;};int sum;//huffman树中结点的个数;huff_tree huffman[1000];void creathuffman()//构造huffman树的函数{int min1,min2;//指示权值最小;int loc1,loc2;//指向权值最小的两个数的位置;for(int i=1;i<=sum;i++){ //对huffman树的结点进行初始化;huffman[i].parent=0;huffman[i].lchild=0;huffman[i].rchild=0;huffman[i].weight=0;}for(int ii=1;ii<Count;ii++)//将权值赋给huffman[].weight;huffman[ii].weight=huff[ii].Count;sum=2*Count-3;for(int j=Count;j<=sum;j++){loc1=loc2=0;//权值最小的min1=min2=2000000;for(int k=1;k<=j-1;k++)//求权值最小的两个地址;if(huffman[k].parent==0)if(huffman[k].weight<=min1){min2=min1;min1=huffman[k].weight;loc2=loc1;loc1=k;}elseif(huffman[k].weight<=min2){min2=huffman[k].weight;loc2=k;}////////////将求出的两个权值最小的结点合并为新的结点,并将新的结点存入数组中huffman[loc1].parent=j;huffman[loc2].parent=j;huffman[j].lchild=loc1;huffman[j].rchild=loc2;huffman[j].weight=huffman[loc1].weight+huffman[loc2].weight;}}/*******************************构造huffman树的程序部分结束********************************//*************************************huffman编码开始**************************************/struct huffcode{//结构体string bits[100];//存放解码;int start;//int count;//频数string c;//存放字符;};huffcode hcode[100];void huffmancode()//编码函数{int rem,p;int count1=0;for(int y=1;y<=Count;y++){//编码部分;rem=y;hcode[y].start=sum;hcode[y].c=huff[y].data;p=huffman[y].parent;while(p!=0){if(huffman[p].lchild==rem)hcode[y].bits[++count1]='0';else hcode[y].bits[++count1]='1';rem=p;p=huffman[p].parent;}hcode[y].count=count1;count1=0;}cout<<"字符以及其编码:"<<endl;for(int t=1;t<=Count;t++)//输出所编的码;{cout<<"字符"<<hcode[t].c<<";编码:";int r=hcode[t].count;while(r)cout<<hcode[t].bits[r--];cout<<endl;}}/****************************************************************************** ******/string str;void code_huffman_file(){ofstream fp;cout<<"请输入文件名"<<endl<<"例如:huffman1.txt"<<endl;cout<<"该文件用来存放编码后的文件即压缩文件"<<endl;cin>>str;fp.open(str.c_str());if(!fp)//检查文件是否打开。