• C语言 题目 1701: 数据结构-自顶向下的赫夫曼编码


    感觉还是自底向上简单,搜了搜答案貌似看懂了,自己手打了一遍,改写了某些看不懂的地方,又写了注释,希望对你有帮助(^∀^●)ノシ

    题目描述

    在本题中,我们将要讨论的是自顶向下的赫夫曼编码算法。从根出发,遍历整棵赫夫曼树从而求得各个叶子结点所表示的字符串。算法的关键部分可以表示如下:

    在本题中,读入n个字符所对应的权值,生成赫夫曼编码,并依次输出计算出的每一个赫夫曼编码。

    输入格式

    输入的第一行包含一个正整数n,表示共有n个字符需要编码。其中n不超过100。
    第二行中有n个用空格隔开的正整数,分别表示n个字符的权值。

    输出格式

    共n行,每行一个字符串,表示对应字符的赫夫曼编码。

    样例输入

    1. 8
    2. 5 29 7 8 14 23 3 11

    样例输出

    1. 0110
    2. 10
    3. 1110
    4. 1111
    5. 110
    6. 00
    7. 0111
    8. 010

    1. #include<stdio.h>
    2. #include<stdlib.h>
    3. #include<string.h>
    4. typedef struct HuffmanCode{
    5. int weight;
    6. int parent;
    7. int lchild;
    8. int rchild;
    9. }HuffmanCode,*HuffmanTree;
    10. void initialHuffmanCode(HuffmanTree,int,int);//初始化结点
    11. void creatHuffmanTree(HuffmanTree,int,int);//构造哈夫曼树
    12. void HuffmanCoding(char**,HuffmanTree,int);//对哈夫曼树进行编码
    13. void TraverseHuffmanCode(char**,int);//自下而上进行遍历
    14. int sum_(HuffmanTree,int);//求哈夫曼树中所有结点权重和
    15. int main(){
    16. int n;
    17. scanf("%d",&n);
    18. int m=2*n-1;//n个叶子结点共有2*n-1个结点
    19. char **HC=(char**)malloc(n*sizeof(char*));//动态分配内存,可以看成二维数组
    20. HuffmanCode hc[m];//结点
    21. initialHuffmanCode(hc,n,m);
    22. creatHuffmanTree(hc,n,m);
    23. HuffmanCoding(HC,hc,n);
    24. TraverseHuffmanCode(HC,n);
    25. }
    26. void initialHuffmanCode(HuffmanTree ht,int n,int m){
    27. for(int i=0;i<m;i++){
    28. if(i<n){
    29. scanf("%d",&(ht[i].weight));
    30. }
    31. ht[i].parent=-1;//初始化为-1
    32. ht[i].lchild=-1;
    33. ht[i].rchild=-1;
    34. }
    35. }
    36. int sum_(HuffmanTree ht,int i){
    37. int sum=0;
    38. for(int j=0;j<i;j++){
    39. if(ht[j].parent==-1)//当某结点的已经成为左或右子树时,此结点不参与运算
    40. sum+=ht[j].weight;
    41. }
    42. return sum;
    43. }
    44. void creatHuffmanTree(HuffmanTree ht,int n,int m){
    45. int min1,min2;//min1为权重最小,min2为次小
    46. int index1,index2;//index1位序最小,index2位序次小
    47. for(int i=n;i<m;i++){
    48. min1=sum_(ht,i);//每次遍历获得当前哈夫曼树权重
    49. min2=min1;
    50. for(int j=0;j<i;j++){//先获得最小权重及下标
    51. if(ht[j].parent==-1){
    52. if(ht[j].weight<min1){
    53. min1=ht[j].weight;//
    54. index1=j;
    55. }
    56. }
    57. }
    58. ht[index1].parent=i;//双亲结点位序赋值
    59. for(int j=0;j<i;j++){//获得次小权重及下标
    60. if(ht[j].parent==-1){
    61. if(ht[j].weight<min2){
    62. min2=ht[j].weight;
    63. index2=j;
    64. }
    65. }
    66. }
    67. ht[index2].parent=i;
    68. ht[i].weight=min1+min2;
    69. if(index1>index2){//需要注意,这里需要比较一下最小和次小的位序!!!
    70. int t=index2;
    71. index2=index1;
    72. index1=t;
    73. }
    74. ht[i].lchild=index1;//左子树为最小位序,右子树为次小位序
    75. ht[i].rchild=index2;
    76. }
    77. }
    78. void HuffmanCoding(char** HC,HuffmanTree ht,int n){
    79. int m=2*n-2;//因为下标从0开始,所以m值设为2*n-2
    80. int cnt=0;//编码字符下标
    81. char* p=(char*)malloc(sizeof(char)*n+1);//因为不确定n个结点最大编码长度为多少,所以分配内存为n+1
    82. for(int i=0;i<2*n-1;i++){
    83. ht[i].weight=0;//初始化,全设置为0
    84. }
    85. while(m!=-1){//当最终遍历回到根结点时,也就是根结点的parent==-1时,停止遍历
    86. if(ht[m].lchild==-1){//因为哈夫曼树只有度为02的结点,没有左孩子,也就是没有右孩子,开始拷贝
    87. p[cnt]='\0';
    88. HC[m]=(char*)malloc(sizeof(char)*(cnt+1));
    89. strcpy(HC[m],p);
    90. m=ht[m].parent;//这里直接返回其父结点
    91. cnt--;
    92. continue;//不再执行剩余语句,回到根结点重新判断
    93. }
    94. if(ht[m].weight==0){//当weight为0时,访问其左结点
    95. ht[m].weight++;//当前结点weight++,代表访问过一次
    96. if(ht[m].lchild!=-1){//当前结点有左孩子,让左孩子成为下一个新根结点
    97. m=ht[m].lchild;
    98. p[cnt++]='0';//路径为'0'
    99. }
    100. }
    101. else if(ht[m].weight==1){//当访问次数为一时,表示访问过它的左结点,现在开始访问他的右结点
    102. ht[m].weight++;//访问次数加一
    103. if(ht[m].rchild!=-1){
    104. m=ht[m].rchild;
    105. p[cnt++]='1';
    106. }
    107. }
    108. else{//当访问次数为二时,也返回它的父结点,cnt减一
    109. m=ht[m].parent;
    110. cnt--;
    111. }
    112. }
    113. }
    114. void TraverseHuffmanCode(char** HC,int n){//遍历
    115. for(int i=0;i<n;i++){
    116. printf("%s\n",HC[i]);
    117. }
    118. }

  • 相关阅读:
    微信小程序的医院体检预约管理系统springboot+uniapp+python
    架构师进阶,微服务设计与治理的16条常用原则
    Alook获取站点cookie详细教程
    读懂AUTOSAR规范,之CanIf 发送缓冲(带实例代码)
    程序员需知的8个视频教程网站,建议收藏
    SpringBoot配置文件
    python中枚举、得出序号enumerate函数,返回整数的divmod(a,b)函数介绍,python中商、余数的计算方法
    netty系列之:netty中的核心MessageToByte编码器
    数字时钟制作
    node.js - 上传文件至阿里云oss
  • 原文地址:https://blog.csdn.net/qq_62109928/article/details/127941859