C++实现哈夫曼编码/译码器(数据结构)

设计一个哈夫曼编码、译码系统。对一个ASCII编码的文本文件中的字符进行哈夫曼编码,生成编码文件;反过来,可将编码文件译码还原为一个文本文件。
(1) 从文件中读入任意一篇英文短文(文件为ASCII编码,扩展名为txt);
(2) 统计并输出不同字符在文章中出现的频率(空格、换行、标点等也按字符处理);
(3) 根据字符频率构造哈夫曼树,并给出每个字符的哈夫曼编码;
(4) 图形化输出哈夫曼树、哈夫曼编码;
(5) 将文本文件利用哈夫曼树进行编码,存储成压缩文件(编码文件后缀名.huf)
(6) 用哈夫曼编码来存储文件,并和输入文本文件大小进行比较,计算文件压缩率;
(7) 进行译码,将huf文件译码为ASCII编码的txt文件,与原txt文件进行比较。
[测试数据]文本文件自行选择,至少含3000个字符。
[实现代码]

#include<iostream>
#include<fstream>
#include<queue>
#include<math.h>
using namespace std;
struct Node{
 public:
  Node *right;
  Node *left;
  char data;
  int weight;
  int x[100];
}; 
void InsertionSort(Node*A[],int n){
    for(int i=1;i<n;i++){
  Node *get=A[i];               
        int j=i-1;                 
        while(j>=0&&A[j]->weight>get->weight){
            A[j+1]=A[j];           
            j--;
        }
        A[j+1]=get;
    }
}
Node* father(Node*root,Node*son){
    Node*temp;
    if(root==NULL||son==NULL)
        return NULL;
    if(root->left==son||root->right==son)
        return root;
    temp=father(root->left,son);
    if(temp!=NULL)
        return temp;
    else
        return father(root->right,son);
}
void preorder(Node*root){
    if(root!=NULL) {
        cout<<root->weight<<" ";
        preorder(root->left);
        preorder(root->right);
    }
}
void sumlevel(Node*root,int *count,int l){
    if(root!=NULL) {
        count[l]=count[l]+1;
        sumlevel(root->left,count,l+1);
        sumlevel(root->right,count,l+1);
    }
}
void levelorder(Node*t,int*count){
 queue<Node*>q;
 int x=0,i=0;
 if(t!=NULL){
  Node*p;
  for(int z=0;z<60;z++){
   cout<<" ";
  }
  cout<<t->data<<"("<<t->weight<<")"<<endl;
  x=x+1;
  i=i+1;
  q.push(t);
  while(!q.empty()){
   p=q.front();
   q.pop();
   if(p->left){
    for(int z=0;z<60/(i+1);z++) cout<<" ";
    cout<<p->left->data<<"("<<p->left->weight<<")";
    if(x==count[i]){
     cout<<endl;
     i++;
     x=0;
    }
    x=x+1;
    q.push(p->left);
   }
   if(p->left){
    for(int z=0;z<60/(i);z++) cout<<" ";
    cout<<p->right->data<<"("<<p->right->weight<<")";
    if(x==count[i]){
     cout<<endl;
     i++;
     x=0;
    }
    x=x+1;
    q.push(p->right);
   }
   }
  }
} 
void TreePrint(Node *T,int level)  
{  
    if (T!=NULL) return;
    TreePrint(T->right,level+1);    //打印右子树,并将层次加1  
    for (int i=0;i<level;i++)    //按照递归的层次打印空格  
    {  
        printf("   ");  
    }  
    cout<<T->weight<<endl;  
    TreePrint(T->left,level+1);    //打印左子树,并将层次加1  
}  
int main(){
//打开待压缩文件
 ifstream file("C:\\Users\\wenjian\\start.txt");
 char a;
 Node *root1;
 int n[128]={0};
 int x,i,j,num=0;
 while(!file.eof()){
  file.get(a);
  if(file.fail()) break;
  x=a;
  n[x]++;
 }
 for(i=0;i<128;i++){
  if(n[i]!=0) num++;
 }
 Node *m[num],*mm[num];
 for(i=0;i<num;i++){
  m[i]=new Node;
  m[i]->left=NULL;
  m[i]->right=NULL;
 }
 j=0;
 for(i=0;i<128;i++){
  if(n[i]!=0){
   m[j]->data=i;
   m[j]->weight=n[i];
   j++;
  }
 }
 InsertionSort(m,num);
 Node *p1,*p2,*p,*t;
 j=0;
 for(i=0;i<num;i++){
  mm[i]=m[i];
 }
 for(i=0;i<num-1;i++){
  t=new Node;
  p1=m[i];
  p2=m[i+1];
  t->weight=m[i]->weight+m[i+1]->weight;
  t->left=p1;
  t->right=p2;
  p=t;
  j=i+2;
  while(j<num&&p->weight > m[j]->weight){
   m[j-1]=m[j];
   j=j+1;
  }
  m[j-1]=p;
 }
 root1=m[num-1];
 int zz[100];
 Node *s,*z;
 for(i=0;i<num;i++){
  for(int xx=0;xx<100;xx++){
   zz[xx]=-1;
  }
  s=father(root1,mm[i]);
  z=mm[i];
  j=0;
  while(s!=root1){
   if(s->left==z){
    zz[99-j]=0;
   }
   if(s->right==z){
    zz[99-j]=1;
   }
   z=s; 
   s=father(root1,z);
   j++;
  }
  if(s->left==z) zz[99-j]=0;
  if(s->right==z) zz[99-j]=1;
  x=0;
  for(int xx=g0;xx<100;xx++){
   if(zz[xx]>-1) x++;
  }
  for(int xx=0;xx<100;xx++){
   zz[xx]=zz[xx+100-x];
  }
  for(int xx=x;xx<100;xx++){
   zz[xx]=-1;
  }
  for(int xx=0;xx<100;xx++){
   mm[i]->x[xx]=zz[xx];
  }
 }
 for(i=0;i<num;i++){
  cout<<mm[i]->data<<":"<<mm[i]->weight<<"  "; 
  for(j=0;j<100;j++){
   if(mm[i]->x[j]>=0) cout<<mm[i]->x[j];
  }
  cout<<endl;
 }
 file.close();
 //再次打开文件
 ifstream file1("C:\\Users\\wenjian\\start.txt");
 //生成的中间文件
 ofstream putfile("C:\\Users\\daima\\progress.txt");
 //生成压缩.huf文件
 ofstream assicfile("C:\\Users\\wenjian\\assic.huf");
 int f=0,o=1,w=0;
 while(!file1.eof()){
  file1.get(a);
  if(file1.fail()) break;
  for(i=0;i<num;i++){
   if(mm[i]->data==a){
    for(j=0;j<100;j++){
     o=1;
     if(mm[i]->x[j]==-1) break;
     putfile<<mm[i]->x[j];
     if(f<6){
      for(int d=0;d<6-f;d++){
       o=2*o;
      }
      w=mm[i]->x[j]*o+w;
      f=f+1;
     }
     if(f==6){
      w=mm[i]->x[j]+w;
      f=0;
      char ww=w;
      assicfile<<ww;
      w=0;
     }
    }
   }
  }
 }
 file1.close();
 putfile.close();
// ifstream outfile("progress.txt");
// ofstream infile("end.txt");   /////
 //重新打开中间文件,生成最终解压文件
 ifstream outfile("C:\\Users\\daima\\progress.txt");
 ofstream infile("C:\\Users\\wenjian\\end.txt");
 char y;
 while(!outfile.eof()){
  if(outfile.fail()) break;
  s=root1;
  z=s;
  while(z->left){
   outfile.get(y);
   if(y=='0'){
    s=z;
    z=s->left;
   }
   if(y=='1'){
    s=z;
    z=s->right;
   }
  }
  if(outfile.fail()) break;
  infile<<z->data;
 }
 outfile.close();
 infile.close();
 int sum[20]={0};
 sumlevel(root1,sum,0);
 levelorder(root1,sum);
 int q=1;
 for(i=0;i<8;i++){
  q=q*2;
  if(q>=num) break;
 }
 int zzz=i+1;
 ifstream file2("end.txt");
 while(!file2.eof()){
  if(file2.fail()) break;
  file2.get(a);
  for(i=0;i<zzz;i++){
  }
  if(file2.fail()) break;
 }
 file2.close();
 float g,h;
 cout<<"请分别输入原文件与压缩文件大小:"<<endl;
 cin>>g;
 cin>>h;
 float hh=h/g;
 cout<<"压缩率:"<<1-hh<<endl; 
} 

猜你喜欢

转载自blog.csdn.net/qq_39187019/article/details/86555835