2019.6.24-2019.6.28(实训数据结构) 书籍:《数据结构项目实训教程》 赵君喆,戴文华
6.3树和二叉树应用项目
输入一串字符,建立哈夫曼树,然后编码解码
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<iostream> #include<cstring> #include<fstream> #include<iomanip> #include<algorithm> using namespace std; char A[50]={}; //构建哈夫曼树结点,包含权重,父节点,左孩子和右孩子 typedef struct{ int weight; int parent,lchild,rchild; }HTNode,*HuffmanTree; typedef char **HuffmanCode; //计算不同字符的个数 void Calculate_weight(char a[],char b[],int m,int n,int *w){ int i,j; for(i=0;i<n;i++){ for(j=0;j<m;j++){ if(b[i]==a[j]){ A[i+1]=w[i+1]++; } } } } //找到最小的两个结点 void FindNode(HuffmanTree HT,int n,int &t1,int &t2){ //构建哈夫曼二叉树 HT[0].weight=100; t1=0; t2=0; for(int i=1;i<=n;i++){ if(HT[i].parent==0){ if(HT[i].weight<HT[t2].weight){ if(HT[t2].weight<HT[t1].weight){ t1=t2; } t2=i; } else if(HT[i].weight<HT[t1].weight){ t1=t2; t2=i; } } } } //将Huffman二叉树的结构写入output_tree_info.txt void output_tree_info(HuffmanTree HT,int m){ //将Huffman二叉树的结构表存入文件 output_tree_info.txt int i; //写入output_tree_info.txt ofstream outfile("output_tree_info.txt"); outfile<<"编号 权重 父结点 左孩子 右孩子"<<endl; for(i=1;i<=m;i++){ outfile<<i<<"\t"; outfile<<HT[i].weight<<"\t"; outfile<<HT[i].parent<<"\t"; outfile<<HT[i].lchild<<"\t"; outfile<<HT[i].rchild<<endl; } } //将Huffman编码表写入output_code_info.txt void output_code_info(char b[],HuffmanCode HC,int n){ //将Huffman编码表写入output_code_info.txt int i; //写入output_code_info.txt ofstream outfile("output_code_info.txt"); outfile<<"编码表:"<<"\t"<<"编码频度"<<endl; for(i=1;i<=n;i++){ outfile<<b[i-1]<<":"<<HC[i]<<"\t"<<A[i]+1<<endl; } } //为哈夫曼二叉树进行编码,构造Huffman二叉树HT,并求出n个字符的哈夫曼二叉树 void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n){ //用w存放n个字符的权值,构造哈夫曼树HT //并求出n个字符的哈夫曼编码HC int m,i,t1,t2,start; unsigned c,f; HuffmanTree p; char *cd; m=2*n-1; HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); for(p=HT+1,i=1;i<=n;i++){//前n个结点初始化 p->weight=w[i]; p->parent=0; p->lchild=0; p->rchild=0; } for(;i<=m;i++,p++){//第n+1个顶点到2n-1个顶点初始化 p->weight=0; p->parent=0; p->lchild=0; p->rchild=0; } for(i=n+1;i<=m;i++){//构建哈夫曼树 FindNode(HT,i-1,t1,t2); HT[t1].parent=i; HT[t2].parent=i; HT[i].lchild=t1; HT[i].rchild=t2; HT[i].weight=HT[t1].weight+HT[t2].weight; } output_tree_info(HT,m);//将树结构写入文件 //求每个字符的哈夫曼编码(从叶子结点到根结点逆向进行) HC=(HuffmanCode)malloc((n+1)*sizeof(char*)); cd=(char*)malloc(n*sizeof(char));//分配求编码的工作空间 cd[n-1]='\0';//编码结束符 for(i=1;i<=n;i++){//逐个字符求哈夫曼编码 start=n-1;//编码结束符位置 for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent){//从叶子到根求编码 if(HT[f].lchild==c){ cd[--start]='0'; } else{ cd[--start]='1'; } } //为第i个字符分配空间 HC[i]=(char*)malloc((n-start)*sizeof(char)) ; strcpy(HC[i],&cd[start]);//从cd复制编码串到HC中 } free(cd);//释放空间 } void Output_HuffmanCoding(char a[],char b[],int m,int n,HuffmanCode HC){ //输出Huffman编码 int i,j; printf("字符串转换成的Huffman编码如下:\n"); for(i=0;i<m;i++){ for(j=0;j<m;j++){ if(a[i]==b[j]){ cout<<HC[j+1]<<"\t"; } } } cout<<endl; } void HuffmanDecoding(int n,char b[],HuffmanTree HT){ //对编码的二进制串进行解码 int m=2*n-1; int i=m; char c; printf("\n请输入一串编码:\n"); cin>>c; while((c=='0')||(c=='1')){//判断是否是合法字符 if(c=='0') i=HT[i].lchild;//继续向左查找 else i=HT[i].rchild;//继续向右查找 if(HT[i].lchild==0){//直到分支的末端 printf("\n所得译码为:\n"); printf("%c\n",b[i-1]);//输出对应的符合 i=m;//重新开始找下一个 } cin>>c; } printf("\n"); } int main(){ HuffmanTree HTree; HuffmanCode HCode; char a[100],b[100]; //a为输入的字符串 int i=0,j=0,len=0,n=0,*w; printf("请输入任意一组字符:\n"); gets(a); len=strlen(a); for(i=0;i<len;i++){ for(j=0;j<i;j++){ if(i<len&&a[j]==a[i]){ i++; j=-1; } } if(i<len){ b[n]=a[i]; n++; } } w=(int*)malloc((n+1)*sizeof(int)); for(i=1;i<=n;i++){ //初始化 w[i]=0; } cout<<"----"<<endl; Calculate_weight(a,b,len,n,w);//计算不同字符的个数 cout<<"---"<<endl; HuffmanCoding(HTree,HCode,w,n);//构造Huffman二叉树HT output_code_info(b,HCode,n); printf("\nHuffman各个字符的详细编码如下:\n"); printf("编码表:\t编码频度:\n"); for(i=1;i<=n;i++){ cout<<b[i-1]<<":"<<HCode[i]<<"\t"<<A[i]+1<<endl; } Output_HuffmanCoding(a,b,len,n,HCode);//输出Huffman编码 HuffmanDecoding(n,b,HTree);//对编码的二进制串进行解码 return 0; }