数据结构实训哈夫曼树

哈夫曼编码和译码
基本要求:
 输入为:一段英文或中文的文章(原文)
 对输入的文章构造哈夫曼树生成对应的编码
 输出为:原文所对应的编码(译文)
 根据已经生成的编码表,输入任意的译文可以得到对应的原文

哈夫曼树的定义:给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。

首先先构造一棵哈夫曼树,在构造哈夫曼树的算法中,需要选择根权值最小和次小的树进行合并

//建立哈夫曼树编码表

void HuffmanTree::CreatHuffmanTree(int a[],char b[],int n)
{
       int m=2*n-1;
       nodes= new HuffmanTreeNode[2*n-1];//开辟数组空间
       for(int i=0;i<n;i++)         //初始化结点为-1
       {
              nodes[i].weight=a[i];    //函数头定义的权值数组a[]
              nodes[i].leftChild=-1;        
              nodes[i].rightChild=-1;         
              nodes[i].parent=-1;       
       }
       for(i=n; i<m;i++)         
       {
              int r1=0,r2=0;
              select(r1,r2,i); //合并两个根权值最小的树
              nodes[r1].parent=nodes[r2].parent=i;
              nodes[i].leftChild=r1;
              nodes[i].rightChild=r2;
              nodes[i].parent=-1;
              nodes[i].weight=nodes[r1].weight+nodes[r2].weight;     
       }
       

//查找两个权值最小的树
void HuffmanTree::select(int &r1,int &r2,int n)
{
    r1=r2=-1;                              
    for(int i=0; i<n; i++)
    if(nodes[i].parent==-1)  //找权值最小的双亲节点         
         if(r1==-1)
              r1=i;
         else
if(nodes[r1].weight<nodes[i].weight) 
{   
         r2=r1;//r2等于次小的
         r1=i;//r1等于最大的
  }
       else if(r2==-1||nodes[i].weight<nodes[r2].weight)//找权值第二小的结点
       r2=i;
}


```cpp
在这里插入代码片

建立编码表,根据每一根分支是左还是右,确定相应位编码是0还是1(此代码为左0右1),从叶子节点出发逆向到根结点,将编码倒转使之成为正确的编码

//建立编码表
void HuffmanTree::CreatHuffmanTree(int a[],char b[],int n)
{
       codes=new HuffmanCode[n];        
       for( i=0; i<n; i++)
       {
              codes[i].data=b[i];//将编码后的结果储存在b数组中
              int q=i;
              int p=nodes[i].parent;//p指向结点i的双亲
              int k=0;
              while(p!=-1)//逆向求码
              {
                     if(q==nodes[p].leftChild)
                            codes[i].code[k]='0';   //左0
                     else
                            codes[i].code[k]='1';    //右1
                     k++;//向下往上查找双亲
                     q=p;
                     p=nodes[q].parent;
              }
              codes[i].code[k]='\0';
              recall(codes[i].code,k);  //字符串整合,倒转
              cout<<codes[i].data<<"的编码是:"<<codes[i].code<<endl;
       }
}


//倒转字符串
void HuffmanTree::recall(char c[],int L)   
{
       L=0;
       char temp;
       while(c[L+1]!='\0')//获取当前编码的长度
       {
              L++;
       }
       for(int i=0;i<=L/2;i++)//交换位置
       {
              temp=c[i];
              c[i]=c[L-i];
              c[L-i]=temp;
       }
}



有了哈夫曼树的编码,即可进行编码和译码

//编码
void HuffmanTree::Encode(char *c, char *s,int n)           
{
       while(*c!='\0')                   
       {
              for(int i=0;i<=n-1;i++)   //遍历查找编码
              {
                     if(*c==codes[i].data)   
                     {
                            strcat(s,codes[i].code);//复制连接字符串
                            break;
                     }
              }
              c++;
       }
       cout<<"编码结果为:"<<s<<endl;
}

//译码
void HuffmanTree::Decode(char *s, char *d,int n)  
{
       int z=2*n-2;
       char *p=d;                                 
       while(*s!='\0')//编码的逆过程
       {                                     
              while(nodes[z].leftChild!=-1)  
              {
                     if(*s=='0')  //如果*s==0,给根结点的左孩子的下标值赋值z并把左孩子作为新的根结点                        
                            z=nodes[z].leftChild;//左0
                     else if(*s=='1')
                            z=nodes[z].rightChild;//右1
                     s++;
              }
              *d=codes[z].data;//译码后的结果赋值给指针*d
              d++;
       }
      cout<<endl<<"译码结果为:"<<p<<endl;
}


主要函数就是以上,下面将程序变得完整一点,使其成为可运行的程序
主函数如下:

void  main()
{   
       HuffmanTree HT;  
       //system("color b0");
       //system("color f4");
       cout<<"---------------------------------------"<<endl;    
       cout<<"      欢迎使用哈夫曼编码系统          "<<endl;  
       cout<<"---------------------------------------"<<endl;  
       cout<<"         请输入英文段落:       "<<endl;
       char *A1=new char[50];//定义字符指针,开辟空间设置字符长度
       char *B1=new char[50];
       *B1='\0';//字符串结束标志
       gets(A1);//得到从键盘输入的字符串A1
       int 
       n = HT.sumweight(A1);//计算A1字符串的频率
       char *A2=new char[50];
       for(int i=0;i<=49;i++)
       *(A2+i)='\0';    //到A2+1个字符结束
       cout<<"按任意字符继续。"<<endl;
       getch();
       HT.menu();
    
       while(true)                     
       {
              int w;
              cin>>w;
              switch(w)
              {
              case 1:
                     HT.CreatHuffmanTree(I,H,n);
                     getch();             
              cout<<"按任意字符继续。"<<endl;
            //system("cls");可选择清屏或不清屏
            HT.menu();
                     break;
              case 2:
                      HT.Encode(A1,B1,n);
                      cout<<"按任意字符继续。"<<endl;
            getch();   
            //system("cls");
              HT.menu();
                    break;
       
              case 3:
                     gets(B1);
                     cout<<endl<<"请输入想要翻译的一串二进制编码:"<<endl;
                     gets(B1);
                 HT.Decode(B1,A2,n);
              cout<<"按任意字符继续。"<<endl; 
              getch();
            //system("cls");
              HT.menu();
                     break;

              case 4:
                     cout << endl;
                    cout << "退出成功!" << endl;                    
                    exit(0);
                     break; 
                  default:                
                      cout<<"选择失败,请重新选择!"<<endl;
                     cout<<endl;
                     break;
              }
       }
}


哈夫曼树是带权路径长度最小的树,所以将一段英文里出现字符的频率作为权值来计算


//计算字符出现的频率
int HuffmanTree::sumweight(char *pl)
{
       char *sweight=pl;
       int i=0;
       H[0]=*sweight;
       I[0]=0;
       while(*sweight!='\0')
       {
              for(int j=0;j<=i;j++)           
              {
                     if(H[j]==*sweight)
                     {
                           I[j]++;
                            break;
                     }
              }     
              if(j>i)                 
              {
                     i++;
                     H[i]=*sweight;
                     I[i]=1;
              }
              sweight++;
       }
       cout<<endl<<"统计次数:"<<endl;
       for(int j=0;j<=i;j++)
       cout<<"字符"<<H[j]<<"的频率为"<<I[j]<<endl;
       return i+1;
} 

至此,程序基本已经完善,剩下的函数成员以及结构体可在调试时自行加上。

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
数据结构算法分析》实验报告 姓名 学号_ _____ __年 __月__ __日 上机题目:以静态链表为存储结构,编写给定权值{7,19,2,6,32,3}构造哈夫曼树算法。 (输出以存储结构表示或以树型显示(90度旋转)) 需求分析 1. 输入数据必须为int的整形数据,其数值范围为:-~47 2. 输出的数据格式为:%d 3. 测试数据的数据为:{7,19,2,6,32,3} 详细设计 1. 该程序采用顺序表的存储结构,其数据结构定义如下: #define n 6 #define m 2*n-1 #define max 100typedef struct {int data; int lchild,rchild,prnt; }hufmtree; 所用数据类型中每个操作的伪码算法如下: 创建哈夫曼树 Program hufm(hufmtree t[m]) FOR i=0;i<m;i++ TO t[i].data=0; t[i].lchild=0; t[i].rchild=0; t[i].prnt=0; End FOR 输入结点值 FOR i=n;i<m;i++ TO p1=0;p2=0; small1=max;small2=max FOR j=0;j<=i-1;j++ TO IFt[j].prnt?=0 IF(t[j].data<small1) small2=small1; small1=t[j].data; p2=p1; p1=j;} ELSE IF(t[j].data<small2) small2=t[j].data; p2=j; t[p1].prnt=i+1; t[p2].prnt=i+1; t[i].lchild=p1+1; t[i].rchild=p2+1; t[i].data=t[p1].data+t[p2].data; END IF END FOR END Hufman 调试分析 1. 调试过程中主要遇到哪些问题?是如何解决的? 开始的时候main函数的数据结构类型定义的与主函数不同,而且缺少返回值,导致最 后的结果陷入死循环,通过看书,向同学询问,得以解决。 2. 经验和体会 哈夫曼树又称最优二叉树,此次实验创建哈夫曼树算法,虽然依旧犯了不少错误,但 仍解决了。在其中学习了很多,对树有了更深的了解。 测试结果 附件 见 058詹奇.Cpp ----------------------- 数据结构算法分析实验报告全文共3页,当前为第1页。 数据结构算法分析实验报告全文共3页,当前为第2页。 数据结构算法分析实验报告全文共3页,当前为第3页。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值