现在介绍数据结构中的树,由于不像链表、队列、栈一样可以直接的线性化地理解,树在一定程度上给予我们较大的理解问题。由间及难,一般大多开始研究二叉树。
先附上最近的数据结构作业——Huffman编码,提供实例参考和理解。
1 #include <iostream> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string.h> 5 6 using namespace std; 7 8 typedef struct{ 9 //char data; 10 int weight; 11 int lchild,rchild,parent; 12 }HTNode,*HuffmanTree; 13 14 typedef char **HuffmanCode; 15 16 void menu(){ 17 cout<<"-------------------------------------------------------------------------"<<endl; 18 cout<<"菜单:输入0-6实现以下操作"<<endl; 19 cout<<"0:结束实验!"<<endl; 20 cout<<"1:实现对给定源文件的电文字符统计操作!"<<endl; 21 cout<<"2:根据统计字符结果建立Huffman树!"<<endl; 22 cout<<"3:根据提供正文内容和已经建立好的Huffman树对正文不同字符进行Huffman编码!"<<endl; 23 cout<<"4: 实现BuildCodeFiles函数,将正文内容以Huffman编码生成01代码文件!"<<endl; 24 cout<<"5: 用Huffman编码对给定译文文件进行译码!"<<endl; 25 cout<<"-------------------------------------------------------------------------"<<endl; 26 27 } 28 int Count(char *text,int *w){/**Count返回字符个数,char[]存不同字符,体现种类,w[]存相应的权值**/ 29 30 int s=0,i; 31 char ch; 32 char filename[20];/**?:next[]、w[]动态开数组,对于同一个头地址,后续一个一个添加元素**/ 33 FILE *fp; 34 cout<<"实现电文字符数据统计,输入源文件名:"<<endl; 35 cin>>filename; 36 getchar(); 37 38 while((fp=fopen(filename,"r"))==NULL){ 39 cout<<"无法打开文件!重新输入文件名:"<<endl; 40 cin>>filename; 41 getchar(); 42 } 43 ch=getc(fp);/**问?:fp指针的指向,外层循环先getc,s值正常;若在循环内第一句作为getc开始,ch会在最后在读取一个空字符**/ 44 while(feof(fp)==0){ 45 //ch=getc(fp); 46 if(s==0){ /**第一个字符**/ 47 text[s]=ch; 48 w[s]++; 49 //cout<<text[s]<<w[s]<<endl; 50 s++;/**s超前一位;由于树结构不用0号位而text[]w[]都用0号位,相应赋值的数组下标关系需要注意**/ 51 ch=getc(fp); 52 continue; 53 } 54 for(i=0;i<s;i++){/**每读取成功一个,存入后s++,此处单次循环范围也随之增加*/ 55 if(ch==text[i]){/**若在已存储的text[]中找到 则对应位置权值数组元素++*/ 56 w[i]++; 57 //cout<<text[i]<<w[i]<<endl; 58 break; 59 } 60 } 61 if(i==s){/**未找到,先利用i=S存入,再自加,因为跳出for循环时,i已经++*/ 62 text[i]=ch; 63 w[i]++; 64 //cout<<text[i]<<w[i]<<endl; 65 s++; 66 } 67 ch=getc(fp); 68 } 69 70 fclose(fp); 71 return s;/**?:s-1 **/ 72 } 73 74 void Select(HuffmanTree &HT,int i,int &s1,int &s2){/**选择指定范围内的权值最小的两个结点*/ 75 int j,k; 76 int min1; 77 int min2; 78 for(k=1;k<=i;k++){/**找到每构造一次新的结点时的初态,即最前面的parent=0的结点*/ 79 if(HT[k].parent==0){ 80 j=k; 81 min1=k; 82 min2=k; 83 break; 84 } 85 } 86 for(j=k+1;j<=i;j++){/**min1,min2找法不同*/ 87 if(HT[j].parent==0){ 88 if(HT[j].weight<HT[min1].weight){/**min1:先定最前无双亲为最小,向后推一个再找比他大的,有则有,无,则为k*/ 89 //cout<<HT[j].weight<<HT[min1].weight<<" "; 90 min1=j; 91 //cout<<min1<<endl; 92 } 93 } 94 } 95 /**此时min1有两种情况:为k、不为k*/ 96 for(j=k;j<=i;j++){/**min2:也先定最前无双亲为最小,在定为最小的值即其后找除去min1小于等于最小的;此时包括min1不为k的情况和min1为k且min2在后面找到相应值的情况*/ 97 if(j==min1){ 98 continue; 99 } 100 if(HT[j].parent==0){ 101 if(HT[j].weight<=HT[min2].weight){ 102 min2=j; 103 } 104 } 105 } 106 if(min2==k&&min1==k){/**此时为min1为k且min2在后面找不到k的情况*/ 107 for(k=1;k<=i;k++){ 108 if(HT[k].parent==0&&k!=min1){/**重新找初态,及最前除去min1=k和有双亲的结点*/ 109 j=k; 110 min2=k; 111 break; 112 } 113 } 114 for(j=k+1;j<=i;j++){/**同于min1的找法*/ 115 if(HT[j].parent==0){ 116 if(HT[j].weight<HT[min2].weight){ 117 min2=j; 118 } 119 } 120 } 121 } 122 s1=min1; 123 s2=min2; 124 //cout<<s1<<" "<<s2<<endl; 125 return; 126 } 127 128 void BuildHuffmanTree(HuffmanTree &HT,int *w,int n){/**建立Huffman树*/ 129 if(n<=1){ 130 cout<<"字符个数不大于1,无法构成Huffman树及相应的Huffman编码!!"<<endl; 131 return; 132 } 133 //cout<<w[0]<<w[1]<<w[2]<<w[3]<<endl; 134 int m=2*n-1; 135 int i; 136 HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));/**0号未用,便于直接理解之后的select的位置范围,外层的text[],w[]运用0号位,对应关系注意**/ 137 for(i=1;i<=n;i++){ /**1...n的权即是叶子结点输入Huffman树**/ 138 HT[i].weight=w[i-1];/**w[0]已用,HT[0]未用*/ 139 HT[i].lchild=HT[i].rchild=HT[i].parent=0; 140 } 141 for(;i<=m;i++){/**其他结点初赋值为0**/ 142 HT[i].weight=HT[i].lchild=HT[i].rchild=HT[i].parent=0; 143 } 144 //cout<<HT[1].weight<<HT[2].weight<<HT[3].weight<<HT[4].weight<<endl; 145 int s1=0,s2=0; 146 for(i=n+1;i<=m;i++){ 147 Select(HT,i-1,s1,s2);/**实现挑选,找到最小的两个值,且s1<=s2,注意事项详见Select()**/ 148 HT[s1].parent=i; 149 HT[s2].parent=i; 150 HT[i].lchild=s1; 151 HT[i].rchild=s2; 152 HT[i].weight=HT[s1].weight+HT[s2].weight; 153 //cout<<HT[s1].weight<<"+"<<HT[s2].weight<<"="<<HT[i].weight<<endl; 154 } 155 return; 156 } 157 158 void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int n){/**Huffman编码,生成HC,编码存储于HC*/ 159 HC=(HuffmanCode)malloc((n+1)*sizeof(char*));/**HC[0]不用,与Huffman树相对应*/ 160 char *cd=(char *)malloc(n*sizeof(char));/**开n个,即叶子结点数*/ 161 cd[n-1]='