哈夫曼树(创建 | 编码) - 图1

    1. #include<stdio.h>
    2. #include<stdlib.h>
    3. #define MAX 100
    4. typedef struct node{
    5. int w;
    6. struct node *lchild,*rchild;
    7. }BiTNode, *BiTree;
    8. BiTree CreateHufferman(int num[], int n);
    9. int GetWPL(BiTree T, int pathLen);
    10. void GetCode(BiTree T, int pathLen);
    11. int main() {
    12. /*
    13. 5
    14. 2 5 7 9 13
    15. */
    16. int n,num[MAX];
    17. BiTree HfmTree;
    18. int i;
    19. int tmp;
    20. // 输入个数
    21. do{
    22. printf("权重个数,最多能输入%d个\n>>> ", MAX);
    23. scanf("%d", &n);
    24. } while (n>MAX); //检查输入是否合法
    25. // 输入数组
    26. printf("输入权重数组(%d个)\n>>> ", n);
    27. for (i=0; i<n; i++) {
    28. scanf("%d", &num[i]);
    29. }
    30. // 创造
    31. HfmTree = CreateHufferman(num, n);
    32. // 计算WPL
    33. tmp = GetWPL(HfmTree, 0); //根结点的路径长度为0
    34. printf("\nWPL:%d\n", tmp);
    35. // 哈夫曼编码
    36. printf("权重\t哈夫曼编码");
    37. GetCode(HfmTree, 0); //根结点的路径长度为0
    38. printf("\n");
    39. return 0;
    40. }
    41. BiTree CreateHufferman(int num[], int n) {
    42. BiTree *tmp; //BiTree[]用于存放n个子树
    43. BiTNode p; //结点
    44. int k1,k2; //k1为最小的下标,k2为次小的下标
    45. int i,j;
    46. //创建一个BiTree[]来存n个子树
    47. tmp = (BiTree *)malloc(sizeof(BiTree) * n);
    48. //创建n个结点,每个结点即是树的根,放到tmp[]中统一管理
    49. for (i=0; i<n; i++) {
    50. tmp[i] = (BiTNode *)malloc(sizeof(BiTNode)); if (!tmp[i]) exit(0);
    51. tmp[i]->w = num[i];
    52. tmp[i]->lchild = tmp[i]->rchild = NULL;
    53. }
    54. //构造哈夫曼树,循环n-1次
    55. for (i=1; i<n; i++) {
    56. //找出tmp[0]至tmp[n]中的前两个
    57. k1 = -1; //k1未选
    58. for (j=0; j<n; j++) {
    59. if (tmp[j]!=NULL && k1==-1) { //找到了第一个
    60. k1 = j;
    61. continue; //找k2
    62. }
    63. if (tmp[j]!=NULL) { //找到了第二个
    64. k2 = j;
    65. break; //退出
    66. }
    67. }
    68. //找出最小的、次小的结点
    69. for (j=k2; j<n; j++) { //从k2开始
    70. if (tmp[j]==NULL) continue; //空树,进入下一轮循环
    71. // 和当前k1、k2比较
    72. if (tmp[j]->w < tmp[k1]->w) { //先和最小的k1比较
    73. // 即 [j] < [k1],j是当前的最小
    74. k2 = k1; //△原来最小的变成了次小
    75. k1 = j; //最小的变成了j
    76. } else if (tmp[j]->w < tmp[k2]->w) { //和次小的比较
    77. // 即[k1] < [j] < [k2]
    78. k2 = j; //次小的为j
    79. }
    80. }
    81. //合并k1,k2
    82. p = (BiTNode *)malloc(sizeof(BiTNode)); if (!p) exit(0);
    83. p->w = tmp[k1]->w + tmp[k2]->w;
    84. p->lchild = tmp[k1];
    85. p->rchild = tmp[k2];
    86. tmp[k1] = p; // 新结点的放到k1的位置
    87. tmp[k2] = NULL; // k2位置为空
    88. }
    89. free(tmp); //删除动态建立的数组tmp[]
    90. //它只是一个BiTNode *的指针数组,而所指结点(即新建的哈夫曼结点)是不会被删除的!
    91. return p; //返回哈夫曼树的根结点
    92. }
    93. int GetWPL(BiTree T, int pathLen) {
    94. // 叶子结点
    95. if (T->lchild==NULL && T->rchild==NULL) {
    96. return T->w * pathLen;
    97. }
    98. return GetWPL(T->lchild, pathLen+1) + GetWPL(T->rchild, pathLen+1);
    99. }
    100. void GetCode(BiTree T, int pathLen) {
    101. static char tmp[2*MAX-1]; //存储编码的结果
    102. int i;
    103. // 叶子结点
    104. if (T->lchild==NULL && T->rchild==NULL) {
    105. printf("\n%d\t", T->w); //结点值
    106. for (i=0; i<pathLen; i++) { //编码值
    107. printf("%c", tmp[i]);
    108. }
    109. return ;
    110. }
    111. //往左走
    112. tmp[pathLen] = '0';
    113. GetCode(T->lchild, pathLen+1);
    114. //往右走
    115. tmp[pathLen] = '1';
    116. GetCode(T->rchild, pathLen+1);
    117. }