数据结构课程设计-(三)哈夫曼编码器
哈夫曼編/譯碼器
任務:建立最優二叉樹函數。
要求:可以建立函數輸入二叉樹,并輸出其哈夫曼樹。
在上交資料中請寫明:存儲結構、基本算法(可以使用程序流程圖)、輸入輸出、源程序、測試數據和結果、算法的時間復雜度、另外可以提出算法的改進方法;
利用哈夫曼編碼進行通信可以大大提高信道利用率,縮短信息傳輸時間,降低傳輸成本。但是,這要求在發送端通過一個編碼系統對待傳數據預先編碼,在接收端將傳來的數據進行譯碼(復原)。對于雙工信道(即可以雙向傳輸信息的信道),每端都需要一個完整的編/譯碼系統。試為這樣的信息收發站寫一個哈夫曼碼的編/譯碼系統。
一個完整的系統應具有以下功能:
(1)I:初始化(Initialization)。從終端讀入字符集大小n,以及n個字符和n個權值,建立哈夫曼樹,并將它存于文件hfmTree中。
(2)E:編碼(Encoding)。利用已建好的哈夫曼樹(如不在內存,則從文件hfmTree中讀入),對文件ToBeTran中的正文進行編碼,然后將結果存入文件CodeFile中。
(3)D:譯碼(Decoding)。利用已建好的哈夫曼樹將文件CodeFile中的代碼進行譯碼,結果存入文件TextFile中。
(4)P:印代碼文件(Print)。將文件CodeFile以緊湊格式顯示在終端上,每行50個代碼。同時將此字符形式的編碼文件寫入文件CodePrin中。
(5)T:印哈夫曼樹(Tree printing)。將已在內存中的哈夫曼樹以直觀的方式(樹或凹入表形式)顯示在終端上,同時將此字符形式的哈夫曼樹寫入文件TreePrint中。
huffman樹的數據結構定義如下:
typedef struct {int weight;int lchild,rchild,parent; } HTNode,*HuffmanTree;(一)哈夫曼樹的建立
1.從所給數據中選擇兩個最小的值
2.根據輸入的字符和權值建立哈夫曼樹
void CreatHuffmanTree(HuffmanTree &HT,int n) {if(n<=1)return ;int m=2*n-1;//樹共有2n-1個節點HT=(HuffmanTree)malloc(sizeof(HTNode)*(m+1));//從1開始多申請一個for(int i=1; i<=m; i++)//初始化{HT[i].lchild=0;HT[i].parent=0;HT[i].rchild=0;HT[i].weight=0;}for(int i=1; i<=n; i++)cin>>HT[i].weight;int s1,s2;for(int i=n+1; i<=m; i++)//后n-1個節點的創建{Select(HT,i-1,s1,s2);//新節點的權值為兩個最小的權值和HT[s1].parent=i;HT[s2].parent=i;HT[i].lchild=s1;HT[i].rchild=s2;HT[i].weight=HT[s1].weight+HT[s2].weight;}return ; }(二)根據哈夫曼樹對字符進行編碼
void CreatHuffmanCode(HuffmanTree &HT,char ** &HC,int n) {char *col;HC=(char **)malloc(sizeof(char *)*(n+1));col=(char *)malloc(sizeof(char)*n);//存儲每個編碼的臨時空間col[n-1]='\0';//為什么是n-1,n個節點創建的哈夫曼樹高為n-1//路徑條數為n-2,最長的只有n-2個數字。for(int i=1; i<=n; i++){int str=n-1;int p=i,f=i;while(HT[f].parent!=0)//從葉向上尋找{f=HT[f].parent;if(HT[f].lchild==p)col[--str]='0';else if(HT[f].rchild==p)col[--str]='1';p=f;}HC[i]=(char *)malloc(sizeof(char)*(n-str)); //為第i個字符編碼分配空間strcpy(HC[i],&col[str]);//復制到編碼中}free(col);return ; }(三)翻譯文件中的碼
void TransCode(HuffmanTree HT,char b[],char a[],char c[],int n) {//b數組是要翻譯的二進制編碼//a數組是葉子對應的字符//c數組存儲翻譯得到的內容FILE *fw;int q=2*n-1; //初始化為根結點的下標int k=0;int len=strlen(b);if((fw=fopen("textfile.txt","w"))==NULL)cout<<"Open file error!"<<endl;for(int i=0; i<len; i++){if(b[i]=='0')q=HT[q].lchild;else if(b[i]=='1')q=HT[q].rchild;if(HT[q].lchild==0&&HT[q].rchild==0)//葉子節點,此時可譯{c[k++]=a[q];fputc(a[q],fw);q=2*n-1;}c[k]='\0';}return ; }(四)對文件中的字符進行編碼
void Coding(HuffmanTree &HT,char ** &HC,int n,char a[]) {FILE *fp,*fw;char c;int k;if((fp=fopen("tobetran.txt","r"))==NULL)cout<<"Open file error!"<<endl;if((fw=fopen("codefile.txt","w"))==NULL)cout<<"Open file error!"<<endl;fscanf(fp,"%c",&c);//從文件中讀取一個字符while(!feof(fp)){for(int i=1; i<=n; i++)if(a[i]==c)//找到對應的編碼{k=i;break;}for(int i=0; HC[k][i]!='\0'; i++)//輸出該字符編碼fputc(HC[k][i],fw);fscanf(fp,"%c",&c);//繼續下一個}fclose(fp);fclose(fw);return ; }(五)打印編碼
void printf_code() {FILE *fp,*fw;char temp;if((fp=fopen("codefile.txt","r"))==NULL)cout<<"error"<<endl;if((fw=fopen("codeprin.txt","w"))==NULL)cout<<"error"<<endl;cout<<"codefile.txt:"<<endl;fscanf(fp,"%c",&temp);for(int i=1;!feof(fp);i++){printf("%c",temp);if(i%50==0)//50個一換行cout<<endl;fputc(temp,fw);//再寫到codeprint文件中fscanf(fp,"%c",&temp);}cout<<endl;cout<<"編碼已存入文件codeprin.txt"<<endl;fclose(fp);fclose(fw); }(六)打印哈夫曼樹
(1)生成空格
(2)打印哈夫曼樹
void printf_tree(int num,HuffmanTree HT) {unsigned char T[100][100];FILE *fp;int m=0;co_tree(T,0,&m,2*num-1,HT);if((fp=fopen("treeprin.txt","w"))==NULL)cout<<"Open file error!"<<endl;for(int i=1;i<=2*num-1;i++){for(int j=0;T[i][j]!='\0';j++){if(T[i][j]==' ')//空格printf(" "),fputc(T[i][j],fp);else//字符printf("%u",T[i][j]),fprintf(fp,"%u",T[i][j]);}cout<<endl;fputc(10,fp);}fclose(fp);return ; }主函數部分:
int main() {char a[100]; //存儲要編碼的所有字符char b[400]; //存儲要翻譯的二進制編碼char c[100]; //存儲翻譯出來的結果HuffmanTree HT=NULL;char ** HC;while(1){char s1[]= {"結點"},s2[]= {"字符"},s3[]= {"權值"},s4[]= {"雙親"},s5[]= {"左孩子"},s6[]= {"右孩子"};int flag=1,choose,num,cc=0;menu();char temp;cout<<"選擇操作:";cin>>choose;switch(choose){case 1:cout<<"輸入字符個數:";cin>>num;cout<<"依次輸入"<<num<<"個字符:";for(int i=1; i<=num; i++)cin>>a[i];cout<<"依次輸入"<<num<<"個字符的權值:";CreatHuffmanTree(HT,num);//cout<<"結點i"<<"\t字符"<<"\t權值"<<"\t雙親"<<"\t左孩子"<<"\t右孩子"<<endl;//for(int i=1; i<=num*2-1; i++)//cout<<i<<"\t"<<a[i]<<"\t"<<HT[i].weight<<"\t"<<HT[i].parent<<"\t"<<HT[i].lchild<<"\t"<<HT[i].rchild<<endl;FILE *fp;if((fp=fopen("hfmtree.txt","w"))==NULL)cout<<"error"<<endl;fwrite(&s1,sizeof(s1),1,fp);fwrite(&s2,sizeof(s2),1,fp);fwrite(&s3,sizeof(s3),1,fp);fwrite(&s4,sizeof(s4),1,fp);fwrite(&s5,sizeof(s5),1,fp);fwrite(&s6,sizeof(s6),1,fp);fputc(10,fp);//10=/nfor(int i=1; i<=2*num-1; i++){fprintf(fp,"%-3d ",i);fwrite(&a[i],1,1,fp);/*fprintf(fp," %-3d ",HT[i].weight);fprintf(fp,"%-3d ",HT[i].parent);fprintf(fp,"%-3d ",HT[i].lchild);fprintf(fp,"%-3d ",HT[i].rchild);fputc(10,fp);*/}fclose(fp);break;case 2:CreatHuffmanCode(HT,HC,num);cout<<"結點i\t"<<"字符\t"<<"權值\t"<<"編碼\t"<<endl;for(int i=1; i<=num; i++)cout<<i<<"\t"<<a[i]<<"\t"<<HT[i].weight<<"\t"<<HC[i]<<endl;break;case 3:Coding(HT,HC,num,a);cout<<"二進制編碼已存入codefile.txt"<<endl;break;case 4:cout<<"從codefile.txt文件中讀取進行譯碼:"<<endl;if((fp=fopen("codefile.txt","rb"))==NULL)cout<<"error"<<endl;while(1){temp = fgetc(fp); //讀一個字節。if(temp == EOF) break; //到文件尾,退出循環。b[cc++] =temp ;//賦值到字符數組中。}b[cc]='\0';printf("%s\n",b);fclose(fp);TransCode(HT,b,a,c,num);cout<<"譯碼結果:";printf("%s\n",c);cout<<"翻譯結果已存入textfile.txt"<<endl;break;case 5:printf_code();break;case 6:cout<<"打印哈夫曼樹:"<<endl;printf_tree(num,HT);break;case 7:flag=0;break;default:cout<<"輸入有誤,重新輸入"<<endl;continue;}if(flag==0)break;}return 0; }總結
以上是生活随笔為你收集整理的数据结构课程设计-(三)哈夫曼编码器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前端学习(2534)vue源码解析
- 下一篇: 拳王公社:网络操盘手必备的400款新媒体