哈夫曼树的实现


核心算法如下

PhuffmanTree createHuffmanTree(int * a, int n) {
  PhuffmanTree p[n];
  PhuffmanTree ptr, root = NULL;
  int i, j;

  for (i = 0; i < n; i++) {
    ptr = (PhuffmanTree)malloc(sizeof(huffmanTreeNode));
    ptr->value = a[i];
    ptr->left = ptr->right = NULL;
    p[i] = ptr;
  }

  for (i = 1; i < n; i++) {
    int k1 = -1, k2;
    for (j = 0; j < n; j++) {
      if (p[j] != NULL && k1 == -1) {
        k1 = j;
        continue;
      }

      if (p[j] != NULL) {
        k2 = j;
        break;
      }
    }

    for (j = k2; j < n; j++) {
      if (p[j] != NULL) {
        if (p[j]->value < p[k1]->value) {
          k2 = k1;
          k1 = j;
        } else if (p[j]->value < p[k2]->value) {
          k2 = j;
        }
      }
    }

    root = (PhuffmanTree)malloc(sizeof(huffmanTreeNode));
    root->value = p[k1]->value + p[k2]->value;
    root->left = p[k1];
    root->right = p[k2];

    p[k1] = root;
    p[k2] = NULL;
  }

  return root;
}

电报通信中,电文是以二进制的0、1序列传送的,每个字符对应一个二进制编码,为了缩短电文的总长度,采用不等长编码方式,构造哈夫曼树,

将每个字符的出现频率作为字符结点的权值赋予叶子结点,每个分支结点的左右分支分别用0和1编码,从树根结点到每个叶子结点的路径上

所经分支的0、1编码序列等于该叶子结点的二进制编码。所示的哈夫曼编码如下:




13:00

15:01

18:11

8:100

5:1011

2:10100

3:10101



具体实现如下

#include<stdio.h>
#include<stdlib.h>
typedef struct huffmanTree * Tree;

typedef struct huffmanTree {
  int value;
  Tree left;
  Tree right;
}huffmanTreeNode, * PhuffmanTree;

PhuffmanTree createHuffmanTree(int * a, int n) {
  PhuffmanTree p[n];
  PhuffmanTree ptr, root = NULL;
  int i, j;

  for (i = 0; i < n; i++) {
    ptr = (PhuffmanTree)malloc(sizeof(huffmanTreeNode));
    ptr->value = a[i];
    ptr->left = ptr->right = NULL;
    p[i] = ptr;
  }

  for (i = 1; i < n; i++) {
    int k1 = -1, k2;
    for (j = 0; j < n; j++) {
      if (p[j] != NULL && k1 == -1) {
        k1 = j;
        continue;
      }

      if (p[j] != NULL) {
        k2 = j;
        break;
      }
    }

    for (j = k2; j < n; j++) {
      if (p[j] != NULL) {
        if (p[j]->value < p[k1]->value) {
          k2 = k1;
          k1 = j;
        } else if (p[j]->value < p[k2]->value) {
          k2 = j;
        }
      }
    }

    root = (PhuffmanTree)malloc(sizeof(huffmanTreeNode));
    root->value = p[k1]->value + p[k2]->value;
    root->left = p[k1];
    root->right = p[k2];

    p[k1] = root;
    p[k2] = NULL;
  }

  return root;
}

int caculateWeightLength(PhuffmanTree pTree, int len) {
  if (!pTree) {
    return 0;
  } else {
    if (pTree->left == NULL && pTree->right == NULL) {
      return pTree->value * len;
    } else {
      return caculateWeightLength(pTree->left, len+1) + caculateWeightLength(pTree->right, len+1);
    }
  }
}

void huffmanCode(PhuffmanTree pTree, int len) {
  static int arr[20];
  if (pTree) {
    if (pTree->left == NULL && pTree->right == NULL) {
      printf("节点权值为%d的编码:", pTree->value);
      for (int i = 0; i < len; i++) {
        printf("%d", arr[i]);
      }
      putchar('\n');
    } else {
      arr[len] = 0;
      huffmanCode(pTree->left, len+1);
      arr[len] = 1;
      huffmanCode(pTree->right, len+1);
    }
  }
}

void printNode(PhuffmanTree node) {
  if (node->left == NULL && node->right == NULL) {
    printf("叶子节点x = %d\n\n", node->value);
    return ;
  }

  if (node->left != NULL) {
    printf("x = %d为哈夫曼树中左子树节点是lnode = %d\n", node->value, node->left->value);
  }

  if (node->right != NULL) {
    printf("x = %d为哈夫曼树中右子树节点是rnode = %d\n", node->value, node->right->value);
  }
  putchar('\n');
}

void prePrint(PhuffmanTree pTree) {
  if (!pTree) {
    return ;
  } else {
    printNode(pTree);
    prePrint(pTree->left);
    prePrint(pTree->right);
  }
}

void midPrint(PhuffmanTree pTree) {
  if (!pTree) {
    return ;
  } else {
    midPrint(pTree->left);
    printf("%d ", pTree->value);
    midPrint(pTree->right);
  }
}

void postPrint(PhuffmanTree pTree) {
  if (!pTree) {
    return ;
  } else {
    postPrint(pTree->left);
    postPrint(pTree->right);
    printf("%d ", pTree->value);
  }

}

void giveNum(int * a, int n) {
  for (int i = 0; i < n; i++) {
    scanf("%d", &a[i]);
  }
}

int main(void)
{
  int arr[] = {}, n, flag;

  printf ("输入带权节点个数:");
  scanf("%d", &n);
  giveNum(arr, n);
  PhuffmanTree root = createHuffmanTree(arr, n);
  printf("1.中序遍历   2.先序遍历哈夫曼树节点关系   3.后序遍历\n");
  printf("4.带权路径长度   5.哈夫曼树编码   6.创建哈夫曼树   7.退出\n");

  while (scanf("%d", &flag) != EOF && flag != 7) {
    switch (flag) {
      case 1: midPrint(root);printf("\n\n");break;
      case 2: printf("哈夫曼树节点关系如下\n");prePrint(root);break;
      case 3: postPrint(root);printf("\n\n");break;
      case 4: printf("带权路径长度\n");printf("WeightLength=%d\n\n",
                                        caculateWeightLength(root,0));break;
      case 5:printf("各节点编码如下:\n");huffmanCode(root,0);putchar('\n');break;
      case 6:printf ("输入带权节点个数:");scanf("%d", &n);giveNum(arr, n);
              root = createHuffmanTree(arr, n);break;
    }
    printf("1.中序遍历   2.先序遍历哈夫曼树节点关系   3.后序遍历\n");
    printf("4.带权路径长度   5.哈夫曼树编码   6.创建哈夫曼树   7.退出\n");
  }

  return 0;
}


结果如图所示





  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值