一.实验目的
练习树和哈夫曼树的有关操作,和各个算法程序,理解哈夫曼树的编码和译码 。
二.实验内容
1. 根据给出的字符以及这些字符的使用频率构建哈夫曼树。
2. 根据哈夫曼树对字符进行哈夫曼编码,并保存这些编码。
三.实验步骤
1. 建立哈夫曼树的存储结构和哈夫曼编码的存储结构。
2. 建立哈夫曼树的函数;
3. 哈夫曼编码的函数;
4. 哈夫曼编码的解码函数
1. #include<iostream> 2. #include <cstring> 3. using namespace std; 4. typedef struct 5. { 6. int weight; 7. int parent,lchild,rchild; 8. }HTNode,*HuffmanTree; 9. typedef char **HuffmanCode; 10. 11. void Select(HuffmanTree HT,int len,int &s1,int &s2) 12. { 13. int i,min1=0x3f3f3f3f,min2=0x3f3f3f3f;//先赋予最大值 14. for(i=1;i<=len;i++) 15. { 16. if(HT[i].weight<min1&&HT[i].parent==0) 17. { 18. min1=HT[i].weight; 19. s1=i; 20. } 21. } 22. int temp=HT[s1].weight;//将原值存放起来,然后先赋予最大值,防止s1被重复选择 23. HT[s1].weight=0x3f3f3f3f; 24. for(i=1;i<=len;i++) 25. { 26. if(HT[i].weight<min2&&HT[i].parent==0) 27. { 28. min2=HT[i].weight; 29. s2=i; 30. } 31. } 32. HT[s1].weight=temp;//恢复原来的值 33. } 34. 35. //用算法5.10构造赫夫曼树 36. void CreatHuffmanTree(HuffmanTree &HT,int n) 37. { 38. //构造赫夫曼树HT 39. int m,s1,s2,i; 40. if(n<=1) return; 41. m=2*n-1; 42. HT=new HTNode[m+1]; //0号单元未用,所以需要动态分配m+1个单元,HT[m]表示根结点 43. for(i=1;i<=m;++i) //将1~m号单元中的双亲、左孩子,右孩子的下标都初始化为0 44. { HT[i].parent=0; HT[i].lchild=0; HT[i].rchild=0; } 45. cout<<"请输入叶子结点的权值:\n"; 46. for(i=1;i<=n;++i) //输入前n个单元中叶子结点的权值 47. cin>>HT[i].weight; 48. /*――――――――――初始化工作结束,下面开始创建赫夫曼树――――――――――*/ 49. for(i=n+1;i<=m;++i) 50. { //通过n-1次的选择、删除、合并来创建赫夫曼树 51. Select(HT,i-1,s1,s2); 52. //在HT[k](1≤k≤i-1)中选择两个其双亲域为0且权值最小的结点, 53. // 并返回它们在HT中的序号s1和s2 54. HT[s1].parent=i; 55. HT[s2].parent=i; 56. //得到新结点i,从森林中删除s1,s2,将s1和s2的双亲域由0改为i 57. HT[i].lchild=s1; 58. HT[i].rchild=s2 ; //s1,s2分别作为i的左右孩子 59. HT[i].weight=HT[s1].weight+HT[s2].weight; //i 的权值为左右孩子权值之和 60. } //for 61. } 62. // CreatHuffmanTree 63. void CreatHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n) 64. { 65. //从叶子到根逆向求每个字符的赫夫曼编码,存储在编码表HC中 66. int i,start,c,f; 67. HC=new char*[n+1]; //分配n个字符编码的头指针矢量 68. char *cd=new char[n]; //分配临时存放编码的动态数组空间 69. cd[n-1]='\0'; //编码结束符 70. for(i=1;i<=n;++i) 71. { //逐个字符求赫夫曼编码 72. start=n-1; //start开始时指向最后,即编码结束符位置 73. c=i; 74. f=HT[i].parent; //f指向结点c的双亲结点 75. while(f!=0) 76. { //从叶子结点开始向上回溯,直到根结点 77. --start; //回溯一次start向前指一个位置 78. if(HT[f].lchild==c) 79. cd[start]='0'; //结点c是f的左孩子,则生成代码0 80. else 81. cd[start]='1'; //结点c是f的右孩子,则生成代码1 82. c=f; 83. f=HT[f].parent; //继续向上回溯 84. } //求出第i个字符的编码 85. HC[i]=new char[n-start]; // 为第i 个字符编码分配空间 86. strcpy(HC[i], &cd[start]); //将求得的编码从临时空间cd复制到HC的当前行中 87. } 88. delete cd; //释放临时空间 89. } // CreatHuffanCode 90. void show(HuffmanTree HT,HuffmanCode HC) 91. { 92. for(int i=1;i<=sizeof(HC)+1;i++) 93. cout<<HT[i].weight<<"编码为"<<HC[i]<<endl; 94. } 95. int main() 96. { 97. HuffmanTree HT; 98. HuffmanCode HC; 99. int n; 100. cout<<"请输入叶子结点的个数:\n"; 101. cin>>n; //输入赫夫曼树的叶子结点个数 102. CreatHuffmanTree(HT,n); 103. CreatHuffmanCode(HT,HC,n); 104. show(HT,HC); 105. return 0; 106. }