哈夫曼编译课程设计
Ⅰ 哈夫曼编、译码器
这个是我课程设计弄的,也是哈弗曼编码译码器
#include<iostream>
#include<stdlib.h>
#include<string.h>
using namespace std;
typedef struct{
     int weight;
  int parent,lchild,rchild;
  int asc;
}HTNode,*HuffmanTree;    //定义赫夫曼存储结构
struct node{
      int ASCII;
      int n;
};
struct node a[127];
struct node w[127];    
//一些全局变量
int count;
HTNode H_T[250];
char ** HC;
char filename[20];
//函数声明
void menu1();     //菜单1
HuffmanTree HeapSort(HuffmanTree HT,int length);    //堆排序
void MinHeapify(HuffmanTree HT, int k,int len);     //调整成一个小顶堆
void buildMinHeap(HuffmanTree HT,int len);          //建一个小顶堆
void swap(HTNode &t1,HTNode &t2);                   //交换两结构体
void savefile();                            //把输入的英文文章保存到文件
void loadfile();                           //从文件中读取文章
HuffmanTree CreateHuffman(HuffmanTree &HT,struct node *w,int n);    //建立赫夫曼数并存入文件
void BianMa(HuffmanTree HT,int n );                                  //字符编码
void BianMa_all(HuffmanTree HT,char**HC,char *filename);             //整篇文章编码
int loadfile2();                                         //从文件读入文章
void JieMa();                                            //解码
//主函数
int main()
{    
    char s;
 while(s!='0')
 {
                system("cls");
             cout<<"\n\n\n";
                cout<<"\t\t\t\t赫夫曼编码/译码器"<<endl<<endl<<endl<<endl<<endl;
             cout<<"\t\t\t\t  1.编码"<<endl<<endl<<endl<<endl;
             cout<<"\t\t\t\t  2.译码"<<endl<<endl<<endl<<endl;
             cout<<"\t\t\t\t  0.退出"<<endl<<endl<<endl<<endl;
             cout<<"\t请输入0—2进行选择,按回车确认";
             cin>>s;
          switch(s)
    {
        case '1':  menu1(); break;
        case '2':
      { 
       system("cls"); 
       JieMa();
       system("pause");
       break;
      }
  
    }
     
 }
}
//菜单1 
void menu1(){
    char s;
 int i;
 int a;
 char c;
 char fpname[20]="article.txt";
 HuffmanTree HT;
while(s!='0'){
 
       system("cls");
       cout<<"\n\t\t\t\t编码界面";
       cout<<"\n\n\n\t\t\t\t1.输入英文文章"<<endl;
       cout<<"\n\n\t\t\t\t2.从文件中读入文章"<<endl;
       cout<<"\n\n\t\t\t\t0.返回上一层"<<endl;
          cout<<"\n\t请输入0—2进行选择,按回车确认";
       cin>>s;
  switch(s){
       case'1': 
    system("cls");
       savefile();
    loadfile();
    CreateHuffman(HT,w,count);
    BianMa(HT,count);
    BianMa_all(HT,HC,fpname);
    system("cls");
    cout<<"出现字符种类共计:";
    cout<<count<<endl;
    for(i=1;i<=count;i++)
    { a=HT[i].asc;
      c=(char)a;
cout<<"________________________________________________________________________________"<<endl;
      cout<<"\t\t\t字符:";
      cout<<c<<endl;
      cout<<"\t\t\tASCII码:";
      cout<<a<<endl;
      cout<<"\t\t\t频数:";
      cout<<HT[i].weight<<endl;
      cout<<"\t\t\t赫夫曼编码:";
      cout<<HC[i]<<endl;
}
    cout<<"________________________________________________________________________________";
    cout<<"\n\t\t整篇文章的编码已存入文件“赫夫曼编码.txt”"<<endl;
    
    system("pause");
    break;
 
 case'2': 
       system("cls");
       if(loadfile2())
    { system("pause");
    return;}
             CreateHuffman(HT,w,count);
    BianMa(HT,count);
    BianMa_all(HT,HC,filename);
    system("cls");
    cout<<"出现字符种类共计:";
    cout<<count<<endl;
    for(i=1;i<=count;i++)
    { a=HT[i].asc;
      c=(char)a;
cout<<"________________________________________________________________________________"<<endl;
      cout<<"\t\t\t字符:";
      cout<<c<<endl;
      cout<<"\t\t\tASCII码:";
      cout<<a<<endl;
      cout<<"\t\t\t频数:";
      cout<<HT[i].weight<<endl;
      cout<<"\t\t\t赫夫曼编码:";
      cout<<HC[i]<<endl;
}
    cout<<"________________________________________________________________________________";
    cout<<"\n\t\t整篇文章的编码已存入文件“赫夫曼编码.txt”"<<endl;
    system("pause");
    break;
   }
}
 
}
//交换结构体
void swap(HTNode &t1,HTNode &t2)
{
   HTNode m;
   
 m = t1;
 t1 = t2;
 t2 = m;
 }
//从键盘输入文章并保存
void savefile(){
 
 FILE *fp;
 char article;
 if((fp=fopen("article.txt","w"))==NULL){
        printf("打开文件不成功!");
  exit(0);
     }
 cout<<"请输入英文文章,以#结束:";
    getchar();
 article=getchar();
 while(article!='#'){
 
  fputc(article,fp);
     
  article=getchar();
 }
   fclose(fp);
}
//从文件读取文章,并统计字符出现频数
void loadfile(){
FILE *fp;
 char ch;
 int i,k,j=0;
 count=0;
 for(i=0;i<=127;i++)   //把所有字符的ascii码存在数组
 { a[i].ASCII=i;
   a[i].n=0;
   
 }
 if((fp=fopen("article.txt","r"))==NULL){
 
   printf("打开文件不成功!");
   exit(0);
 }
       ch=fgetc(fp);
       k=(int)ch;
    a[k].n++;
      while(!feof(fp)){
       ch=fgetc(fp);
    k=(int)ch;
       a[k].n++;
       }
   fclose(fp);
    
  for(i=0;i<=127;i++)      //统计字符种类总数
  {
  ch=(char)i;
  if(a[i].n){
   count++;
  }
  }
  for(i=0;i<=127;i++)
  {  
   for(;j<count;)
   {
    if(a[i].n)
    {
    w[j].n=a[i].n;
    w[j].ASCII=a[i].ASCII;
    j++;
    break;
    }
     else break;
   }
   }
  
}
//调整为小顶堆
void MinHeapify(HuffmanTree HT, int k,int len)   
{
    int left=k*2;
    int right=k*2+1;
    int large;
 int l=len;
    
    large = k;
    if (left<=l&&HT[left].weight<HT[large].weight)
        large = left;
    if (right<=l&& HT[right].weight<HT[large].weight)
        large=right;
    
    if (large!=k)
    {
        swap(HT[k],HT[large]);
        MinHeapify(HT,large,l);
    }
}
//建立小顶堆
void buildMinHeap(HuffmanTree HT,int len)  
{
    int i;
    for (i=len/2;i>=1;i--)
    {
        MinHeapify(HT,i,len);
    }
}
//堆排序
HuffmanTree HeapSort(HuffmanTree HT,int length)
{
    int i;
    int l=length;
    buildMinHeap(HT,length);
    for (i=length;i>= 2;i--)
    {
        swap(HT[1],HT[i]);
        length--;
        MinHeapify(HT,1,length);
    }
return HT;
}
//建立赫夫曼数
HuffmanTree CreateHuffman(HuffmanTree &HT,struct node *w,int n)
{
    int i,m,s1,s2,k1,k2,j,x,a;
 FILE *fp,*fp2;
if(n<=1) return HT;
    m=2*n-1;
 HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//0不用
  
 for(i=1,j=0;i<=n;i++,j++)
 {   HT[i].asc=w[j].ASCII;
  HT[i].weight=w[j].n;
  HT[i].parent=0;
  HT[i].lchild=0;
  HT[i].rchild=0;
 }
 for(;i<=m;i++)
 { a=250+i;
   HT[i].asc=a;//父亲节点的asc可以是大于127的任意值
   HT[i].weight=0;
   HT[i].parent=0;
   HT[i].lchild=0;
   HT[i].rchild=0;
 }
    for(i=1;i<=n;i++){
 
       H_T[i].asc=HT[i].asc;
    H_T[i].parent=HT[i].parent;
    H_T[i].lchild=HT[i].lchild;
    H_T[i].rchild=HT[i].rchild;
    H_T[i].weight=HT[i].weight;
 }
   
 for(i=n+1,x=n;i<=m;i++,x--)
 {  
  
  HeapSort(H_T,x);
     k1=H_T[x].asc;
  k2=H_T[x-1].asc;
    for(j=1;j<=127;j++)
    {
     if(HT[j].asc==k1)
}
     
       for(j=1;j<=127;j++)
    {  
       if(HT[j].asc==k2)
}
     
    HT[s2].parent=i;
    HT[s1].parent=i;
    HT[i].lchild=s1;
    HT[i].rchild=s2;
    HT[i].weight=HT[s1].weight+HT[s2].weight;
    H_T[x-1].asc=HT[i].asc;
       H_T[x-1].lchild=HT[i].lchild;
       H_T[x-1].parent=HT[i].parent;
       H_T[x-1].rchild=HT[i].rchild;
       H_T[x-1].weight=HT[i].weight;
    
 }
   if((fp2=fopen("count.txt","w"))==NULL)        //保存赫夫曼树
   {   
       cout<<"文件打开不成功!"<<endl;
        exit(0);
   }
    fputc(count,fp2);
   if((fp=fopen("HuffmanTree.dat","wb"))==NULL)
   {  cout<<"文件打开不成功!"<<endl;
      exit(0);
   
   }
     
   for(i=1;i<=(2*count-1);i++){
  fwrite(&HT[i],sizeof(HTNode),1,fp);
   }
   fclose(fp);
   fclose(fp2);
  return HT;
}
//逆向编码
void BianMa(HuffmanTree HT,int n){
   char *cd,temp;
   
   int c,f,i,j,len,p,q;
     
   cd=(char *)malloc(n*sizeof(char));
   HC=(char * *)malloc(n*sizeof(char*));
   for(i=1;i<=n;i++){
  for(c=i,f=HT[i].parent,j=0;f!=0;c=f,f=HT[f].parent,j++)
  {  if(HT[f].lchild==c) cd[j]='0';
   else cd[j]='1';
   if(HT[f].parent==0)
   cd[j+1]='\0';
    
  }
len=strlen(cd);
  for(p=0,q=len-1;p<=q;p++,q--)
  {
   temp=cd[q];
   cd[q]=cd[p];
   cd[p]=temp;
  }
  cd[len]='\0';
  HC[i]=(char*)malloc((len+10)*sizeof(char));
     strcpy(HC[i],cd);
   } 
}
//整篇文章编码,并存入文件
void BianMa_all(HuffmanTree HT,char**HC,char *filename){
      char ch;
   int k,i;
   FILE *fp,*fp2;
   
  char code[100];
  if((fp=fopen(filename,"r"))==NULL){
        printf("打开文件不成功!");
  exit(0);
     }
 if((fp2=fopen("赫夫曼编码.txt","w"))==NULL){
        printf("打开文件不成功!");
  exit(0);
     }
     ch=fgetc(fp);
  k=(int)ch;
  while(!feof(fp))
 {
         
   for(i=1;i<=count;i++)
   {
   if(k==HT[i].asc)
   strcpy(code,HC[i]);
   
   }  
     fputs(code,fp2);
     ch=fgetc(fp);
   k=(int)ch;
  
  }
    fclose(fp);
 fclose(fp2);
}
void JieMa(){
     int i,k,a,t,n=0;
     FILE *fp1,*fp2,*fp3;
  char ch,c;
  HuffmanTree ht;
  if((fp3=fopen("count.txt","r"))==NULL)     //从文件读出字符总数
  {    
        printf("打开文件不成功!");
  exit(0);
  }
       n=fgetc(fp3);
     ht=(HuffmanTree)malloc(2*n*sizeof(HTNode));
    if((fp1=fopen("赫夫曼编码.txt","r"))==NULL)
    {
        printf("打开文件不成功!");
  exit(0);
    }
  if((fp2=fopen("HuffmanTree.dat","rb"))==NULL)
   {  cout<<"文件打开不成功!"<<endl;
      exit(0);
   
   }
for(i=1;i<=2*n-1;i++)
  fread(&ht[i],sizeof(HTNode),1,fp2);
for(i=1;i<=2*n-1;i++)
  {
 if(ht[i].parent==0)
  }       
 
 ch=fgetc(fp1);
 while(!feof(fp1)){
  if(ch=='0')
  {
    k=ht[k].lchild;
    if(ht[k].lchild==0)
    {a=ht[k].asc;
     c=(char)a;
  printf("%c",c);;
  
  k=t;
    }
  }
 if(ch=='1')
 {
  k=ht[k].rchild;
  if(ht[k].lchild==0)
  {  a=ht[k].asc;
     c=(char)a;
  printf("%c",c);
  
  k=t;
  }
  
 }
ch=fgetc(fp1);
 }
  fclose(fp1);
  fclose(fp2);
}
//读取文件中的文章,可自己选择文件
int loadfile2(){
FILE *fp;
 char ch;
 int i,k,j=0;
 count=0;
 for(i=0;i<=127;i++)
 { a[i].ASCII=i;
   a[i].n=0;
   
 }
 cout<<"\n\n\n\t\t\t请输入你要打开的文件名:";
 cin>>filename;
   if((fp=fopen(filename,"r"))==NULL){
 
   printf("打开文件不成功!");
   return 1;
 }
       ch=fgetc(fp);
       k=(int)ch;
    a[k].n++;
      while(!feof(fp)){
       ch=fgetc(fp);
    k=(int)ch;
       a[k].n++;
       }
   fclose(fp);
    
  for(i=0;i<=127;i++){
  ch=(char)i;
  if(a[i].n){
   count++;
  }
 }
  for(i=0;i<=127;i++)
  {  
   for(;j<count;)
   {
    if(a[i].n)
    {
    w[j].n=a[i].n;
    w[j].ASCII=a[i].ASCII;
    j++;
    break;
    }
     else break;
   }
   }
  return 0;
}
Ⅱ 我们有个数据结构的哈夫曼编码解码的课程设计,你能帮帮我吗
树和哈夫曼树实验报告
一.实验目的
练习树和哈夫曼树的有关操作,和各个算法程序,理解哈夫曼树的编码和译码
二.实验环境
     Microsoft visual c++
三.实验问题描述
1. 问题描述:建立一棵用二叉链表方式存储的二叉树,并对其进行遍历(先序、中序和后序),打印输出遍历结果。
基本要求:从键盘接受输入先序序列,以二叉链表作为存储结构,建立二叉树(以先序来建立),并将此二叉树按照“树状形式”打印输出,然后对其进行遍历(先序、中序和后序),最后将遍历结果打印输出。在遍历算法中要求至少有一种遍历采用非递归方法。
测试数据:
ABCØØDEØGØØFØØØ(其中Ø表示空格字符)
输出结果为:
先序:ABCDEGF
先序:CBEGDFA
先序:CGEFDBA
2. 问题描述:利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接受端将传来的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的信息收发站写一个哈夫曼码的编/译码系统。
基本要求:(至少完成功能1-2)
一个完整的系统应具有以下功能:
I:初始化(Initialization)。从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。
基本要求:
E:编码(Encoding)。利用已建好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
D:译码(Decoding )。利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。
P:印代码文件(Print)。将文件CodeFile以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件CodePrint中。
T:印哈夫曼树(TreePrinting)。将已在内存中的哈夫曼树以直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。
测试数据:
设权值w=(5,29,7,8,14,23,3,11),n=8。
     按照字符‘0’或‘1’确定找左孩子或右孩子,则权值对应的编码为:
     5:0001,29:11,7:1110,8:1111
     14:110,23:01,3:0000,11:001
用下表给出的字符集和频度的实际统计数据建立哈夫曼树,并实现以下报文的编码和译码:“THIS PROGRAM IS MY FAVORITE”。
四.实验主要程序流
实验题目一主要程序:
1.
void CreatBiTree(BitTree *bt)//用扩展先序遍历序列创建二叉树,如果是#当前树根置为空,否则申请一个新节点//
{
 char ch;
 ch=getchar();
 if(ch=='.')*bt=NULL;
 else
 {
  *bt=(BitTree)malloc(sizeof(BitNode));
  (*bt)->data=ch;
  CreatBiTree(&((*bt)->LChild));
  CreatBiTree(&((*bt)->RChild));
 }
}
2.void Visit(char ch)//访问根节点
{
 printf("%c  ",ch);
}
3.
void  PreOrder(BitTree root)
{
 if (root!=NULL)
 {
  Visit(root ->data);
  PreOrder(root ->LChild);
  PreOrder(root ->RChild);
 }
}
4. void  InOrder(BitTree root)
 
{
 if (root!=NULL)
 {
  InOrder(root ->LChild); 
  Visit(root ->data);      
  InOrder(root ->RChild); 
 }
}
5.int PostTreeDepth(BitTree bt)   //后序遍历求二叉树的高度递归算法//
{
 int hl,hr,max;
 if(bt!=NULL)
 {
  hl=PostTreeDepth(bt->LChild);  //求左子树的深度
  hr=PostTreeDepth(bt->RChild);  //求右子树的深度
  max=hl>hr?hl:hr;              //得到左、右子树深度较大者
  return(max+1);               //返回树的深度
 }
 else return(0);              //如果是空树,则返回0
}
6.void PrintTree(BitTree Boot,int nLayer)  //按竖向树状打印的二叉树 //
{
    int i;
 if(Boot==NULL) return;
 PrintTree(Boot->RChild,nLayer+1);
 for(i=0;i<nLayer;i++)
  printf("  ");
 printf("%c\n",Boot->data);
 PrintTree(Boot->LChild,nLayer+1);
}
7.void main()
{
 BitTree T;
 int h;
 int layer;
 int treeleaf;
 layer=0;
 printf("请输入二叉树中的元素(以扩展先序遍历序列输入,其中.代表空子树):\n");
    CreatBiTree(&T);
 printf("先序遍历序列为:");
 PreOrder(T);
 printf("\n中序遍历序列为:");
 InOrder(T);
 printf("\n后序遍历序列为:");
 PostOrder(T);
 h=PostTreeDepth(T);
    printf("\此二叉树的深度为:%d\n",h);
 printf("此二叉树的横向显示为:\n");
 PrintTree(T,layer);
}
实验二主要程序流:
1.int main(){
HuffmanTree huftree;     
 char Choose;
 while(1){
  cout<<"\n**********************欢迎使用哈夫曼编码/译码系统**********************\n";
  cout<<"*您可以进行以下操作:                                                 *\n";
cout<<"*1.建立哈夫曼树                                                      *\n";
  cout<<"*2.编码(源文已在文件ToBeTra中,或键盘输入)                          *\n";
  cout<<"* 3.译码(码文已在文件CodeFile中)                                      *\n";
  cout<<"* 4.显示码文                                                          *\n";
  cout<<"* 5.显示哈夫曼树                                                      *\n";
  cout<<"* 6.退出                                                              *\n";  cout<<"***********************************************************************\n";
  cout<<"请选择一个操作:";
  cin>>Choose;
  switch(Choose)
  {
   case '1':
    huftree.CreateHuffmanTree();    
    break;
   case '2':
    huftree.Encoder();
    break;
   case '3':
    huftree.Decoder();
    break;
   case '4':
    huftree.PrintCodeFile();
    break;
   case '5':
    huftree.PrintHuffmanTree();
    break;
   case '6':
    cout<<"\n**********************感谢使用本系统!*******************\n\n";
    system("pause");   
    return 0;
  }//switch
  }//while
}//main
2.// 建立哈夫曼树函数
// 函数功能:建立哈夫曼树(调用键盘建立哈夫曼树或调用从文件建立哈夫曼树的函数)
void HuffmanTree::CreateHuffmanTree()      
{char Choose;       
 cout<<"你要从文件中读入哈夫曼树(按1),还是从键盘输入哈夫曼树(按2)?";
 cin>>Choose;
 if(Choose=='2') {     //键盘输入建立哈夫曼树 CreateHuffmanTreeFromKeyboard();
 }//choose=='2'
 else {      //从哈夫曼树文件hfmTree.dat中读入信息并建立哈夫曼树
  CreateHuffmanTreeFromFile();
 }
}
3. // 从键盘建立哈夫曼树函数
// 函数功能:从键盘建立哈夫曼树
//函数参数:无
//参数返回值:无
void HuffmanTree::CreateHuffmanTreeFromKeyboard(){
  int Num;
  cout<<"\n请输入源码字符集个数:";
  cin>>Num;
  if (Num<=1) {
   cout<<"无法建立少于2个叶子结点的哈夫曼树。\n\n";
   return;
  }
  LeafNum=Num;
  Node=new HuffmanNode[2*Num-1]; 
  for(int i=0;i<Num;i++) {//读入哈夫曼树的叶子结点信息
   cout<<"请输入第"<<i+1<<"个字符值";
   getchar();          
   Node[i].sourcecode=getchar();  //源文的字符存入字符数组Info[]
   getchar();
   cout<<"请输入该字符的权值或频度";
   cin>>Node[i].weight; //源文的字符权重存入Node[].weight      
   Node[i].parent=-1;    
   Node[i].lchild=-1;    
   Node[i].rchild=-1; 
   Node[i].code="\0";
  }
for(int j=Num;j<2*Num-1;j++) {//循环建立哈夫曼树内部结点
   int pos1,pos2;
   int max1,max2;
   pos2=pos1=j;
   max2=max1=numeric_limits<int>::max( );
    //在所有子树的根结点中,选权重最小的两个根结点,pos1最后应指向权重最小的根结点的下标
    //pos2最后应指向权重第二小的根结点的下标      
    //max1存放当前找到的权重最小的根结点的权重
    //max2存放当前找到的权重第二小的根结点的权重
   for(int k=j-1;k>=0;k--) {  
    if (Node[k].parent==-1){//如果是某棵子树的根结点
     if (Node[k].weight<max1){ //发现比当前最大值还大的权重
      max2=max1;          
      max1=Node[k].weight;  
      pos2=pos1;         
      pos1=k;           
     }
     else
      if(Node[k].weight<max2){ //发现比当前次大值还大的次大权重
       max2=Node[k].weight;   
       pos2=k;               
      }
    }//if (Node[j].parent==-1)
   } //for
 //在下标i处新构造一个哈夫曼树的内部结点,其左、右孩子就是以上pos1、pos2所指向的结点
   Node[pos1].parent=j;     
   Node[pos2].parent=j;
   Node[j].lchild=pos1;     
   Node[j].rchild=pos2;
   Node[j].parent=-1;            
   Node[j].weight=Node[pos1].weight+Node[pos2].weight;
  } //for
 
  //产生所有叶子结点中字符的编码
  for (int m=0;m<Num;m++) {
   //产生Node[i].sourcecode的编码,存入Node[i].code中
   int j=m;
   int j1;
   while(Node[j].parent!=-1) { //从叶结点开始往根结点走,每往上走一层,就产生一位编码存入code[]
    j1=Node[j].parent;            
    if(Node[j1].lchild==j)
     Node[m].code.insert(0,"0"); 
    else                     
     Node[m].code.insert(0,"1");
    j=j1; }}
  cout<<"哈夫曼树已成功构造完成。\n";
//把建立好的哈夫曼树写入文件hfmTree.dat
  char ch;
  cout<<"是否要替换原来的哈夫曼树文件(Y/N):";
  cin>>ch;
  if (ch!='y'&&ch!='Y') return;
  ofstream fop;  
  fop.open("hfmTree.dat",ios::out|ios::binary|ios::trunc); //打开文件
  if(fop.fail())  {                 
   cout<<"\n哈夫曼树文件打开失败,无法将哈夫曼树写入hfmTree.dat文件。\n";
   return;
  }
  fop.write((char*)&Num,sizeof(Num)); //先写入哈夫曼树的叶子结点个数
  for(int n=0;n<2*Num-1;n++) { //最后写入哈夫曼树的各个结点(存储在Node[]中)
   fop.write((char*)&Node[n],sizeof(Node[n]));
   flush(cout); }
  fop.close(); //关闭文件
  cout<<"\n哈夫曼树已成功写入hfmTree.dat文件。\n";}
4. // 从文件建立哈夫曼树函数
// 函数功能:从文件建立哈夫曼树
//函数参数:无
//参数返回值:无
void HuffmanTree::CreateHuffmanTreeFromFile(){
  ifstream fip;      
  fip.open("hfmTree.dat",ios::binary|ios::in);
  if(fip.fail())  {
   cout<<"哈夫曼树文件hfmTree.dat打开失败,无法建立哈夫曼树。\n";
   return;     
  }
 fip.read((char*)&LeafNum,sizeof(LeafNum)); 
  if (LeafNum<=1) {
   cout<<"哈夫曼树文件中的数据有误,叶子结点个数少于2个,无法建立哈夫曼树。\n";
   fip.close();
   return;     
  }
  Node=new HuffmanNode[2*LeafNum-1];
  for(int i=0;i<2*LeafNum-1;i++)           
   fip.read((char*)&Node[i],sizeof(Node[i]));
  fip.close();
  cout<<"哈夫曼树已从文件成功构造完成。\n";
}
5. //  编码函数
//  函数功能:为哈夫曼树编码
//函数参数:无
//参数返回值:无
void HuffmanTree::Encoder()
{
 if(Node==NULL) {    //内存没有哈夫曼树,则从哈夫曼树文件hfmTree.dat中读入信息并建立哈夫曼树
  CreateHuffmanTreeFromFile();
  if (LeafNum<=1) {
   cout<<"内存无哈夫曼树。操作撤销。\n\n";
   return;
  }
 }//if
 char *SourceText;    //字符串数组,用于存放源文     
         //让用户选择源文是从键盘输入,还是从源文文件ToBeTran.txt中读入
 char Choose;       
 cout<<"你要从文件中读入源文(按1),还是从键盘输入源文(按2)?";
 cin>>Choose;
 if(Choose=='1') {
  ifstream fip1("ToBeTran.txt");
  if(fip1.fail())    {
   cout<<"源文文件打开失败!无法继续执行。\n";
   return;      
  }
  char ch;
  int k=0;
  while(fip1.get(ch)) k++;     //第一次读文件只统计文件中有多少个字符,将字符数存入k
  fip1.close(); 
  SourceText=new char[k+1];     //申请存放源文的字符数组空间
  ifstream fip2("ToBeTran.txt");    //第二次读源文文件,把内容写入SourceText[]
  k=0;
  while(fip2.get(ch)) SourceText[k++]=ch;         
  fip2.close();
  SourceText[k]='\0';       
 }
 else {     //从键盘输入源文
  string SourceBuff;       
  cin.ignore();
  cout<<"请输入需要编码的源文(可输入任意长,按回车键结束):\n";
  getline(cin,SourceBuff,'\n');   
  int k=0;
  while(SourceBuff[k]!='\0')
   k++;
  SourceText=new char[k+1];
  k=0;
  while(SourceBuff[k]!='\0') {
   SourceText[k]=SourceBuff[k];
   k++;
  }
  SourceText[k]='\0';        
 }
 cout<<"需编码的源文为:";
 cout<<SourceText<<endl;
      //开始译码
 ofstream fop("CodeFile.dat",ios::trunc);    //打开码文存放文件   
                            
 int k=0;
 while(SourceText[k]!='\0')      //源文串中从第一个字符开始逐个编码       
 {
  int i;
  for(i=0;i<LeafNum;i++){     //找到当前要编码的源文的字符在哈夫曼树Node[]中的下标
   if(Node[i].sourcecode==SourceText[k]) {    //将对应编码写入码文文件
    fop<<Node[i].code;
    break;
   };
  }
  if (i>=LeafNum) {
   cout<<"源文中存在不可编码的字符。无法继续执行。\n"<<endl;
   fop.close();
   return;
  }
  k++;     //源文串中的字符后移一个
 }
 fop.close();
 cout<<"已完成编码,码文已写入文件CodeFile.dat中。\n\n";
}
6. //  译码函数
//  函数功能:对哈夫曼树进行译码
//函数参数:无
//参数返回值:无
void HuffmanTree::Decoder()
{//如果内存没有哈夫曼树,则从哈夫曼树文件hfmTree.dat中读入信息并建立哈夫曼树
 if(Node==NULL)     
 {
  CreateHuffmanTreeFromFile();
  if (LeafNum<=1) {
   cout<<"内存无哈夫曼树。操作撤销。\n\n";
   return;
  }
 }
//将码文从文件CodeFile.dat中读入 CodeStr[]
 ifstream fip1("CodeFile.dat");         
 if(fip1.fail()) {
  cout<<"没有码文,无法译码。\n";
  return;
 }
char* CodeStr;
 int k=0;
 char ch;
 while(fip1.get(ch)){
  k++;                    
 }
 fip1.close(); 
  CodeStr=new char[k+1];
 ifstream fip2("CodeFile.dat");
 k=0;
 while(fip2.get(ch))
  CodeStr[k++]=ch;       
 fip2.close();               
 CodeStr[k]='\0';
cout<<"经译码得到的源文为:";
 ofstream fop("TextFile.dat");     
int j=LeafNum*2-1-1;    //j指向哈夫曼树的根     
 
 int i=0;     //码文从第一个符号开始,顺着哈夫曼树由根下行,按码文的当前符号决定下行到左孩子还是右孩子
 while(CodeStr[i]!='\0') {     //下行到哈夫曼树的叶子结点处,则译出叶子结点对应的源文字符
  if(CodeStr[i]=='0')
   j=Node[j].lchild;        
  else
   j=Node[j].rchild;        
  if(Node[j].rchild==-1) {    //因为哈夫曼树没有度为1的结点,所以此条件等同于Node[j]为叶结点
   cout<<Node[j].sourcecode;     //屏幕输出译出的一个源文字符    
   fop<<Node[j].sourcecode;              
   j=LeafNum*2-1-1;     //j再指向哈夫曼树的根       
  }
  i++;
 }
 fop.close();
 
 cout<<"\n译码成功且已存到文件TextFile.dat中。\n\n";
}
7. //  输出码文函数
//  函数功能:从文件中输出哈夫曼树的码文
//函数参数:无
//参数返回值:无
void HuffmanTree::PrintCodeFile()
{
 char ch;
 int i=1;
 ifstream fip("CodeFile.dat");         
 ofstream fop("CodePrin.dat");         
 if(fip.fail())
 {
cout<<"没有码文文件,无法显示码文文件内容。\n";
  return;
 }
 while(fip.get(ch))
 {cout<<ch;          
  fop<<ch;            
  if(i==50)      
  {
   cout<<endl;
   fop<<endl;
   i=0;
  }
  i++;
 }
 cout<<endl;
 fop<<endl;
 fip.close();        
 fop.close();         
}
8. //  输出函数
//  函数功能:从内存或文件中直接输出哈夫曼树
//函数参数:无
//参数返回值:无
void HuffmanTree::PrintHuffmanTree()
{
     //如果内存没有哈夫曼树,则从哈夫曼树文件hfmTree.dat中读入信息并建立哈夫曼树
 if(Node==NULL)     
 {
  CreateHuffmanTreeFromFile();
  if (LeafNum<=1) {
   cout<<"内存无哈夫曼树。操作撤销。\n\n";
   return;  }}
 ofstream fop("TreePrint.dat",ios_base::trunc);
 fop.close();
 PrintHuffmanTree_aoru(2*LeafNum-1-1);
 return;
}
