当前位置:   article > 正文

数据结构--哈夫曼树

哈夫曼树

最新发布博客:算法设计与分析-分治篇 

zhttps://blog.csdn.net/XUN__MLF/article/details/134620313?spm=1001.2014.3001.5502

哈夫曼树及其应用

1、哈夫曼树的基本概念

  • 路径:从树中一个结点到另一个结点之间的分支构成这两个结点间的路径

  • 结点的路径长度:两结点间路径上的分支数。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

  • 树的路径长度:从树根到每一个结点的路径长度之和。记作TL

  • 结点树目相同的二叉树中,完全二叉树是路径长度最短的二叉树

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

  • 权(weight):将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权

  • 1结点的带权路径长度:从根结点到该结点之间的路径长度与该结点的权的乘积

  • 树的带权路径长度:树中所有叶子节点的带权路径长度之和。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

 哈夫曼树:最优树 带权路径长度最短的树

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

满二叉树不一定是最优二叉树

  • 哈夫曼树中权越大的叶子离根越近

  • 具有相同带权结点的哈夫曼树不唯一

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

2、哈夫曼树的构造算法

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

2.1  哈夫曼算法

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

  1. 构造森林全是根

  2. 选用两小造新树

  3. 删除两小添新人

  4. 重复 2、3 剩单根

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

包含n棵树的森林要经过n-1次合并才能形成哈夫曼树,共产生n-1个新结点

包含n个叶子节点的哈夫曼树中共有2n-1个结点

总结:

  1. 在哈夫曼算法中,初始时有n棵二叉树,要经过n-1次合并最终形成哈夫曼树。

  2. 经过n-1此=次合并产生n-1个新结点,且这 n-1 个新结点都是具有两个孩子的分支结点

  3. 哈夫曼树中共有n+n-1 = 2n-1 个结点,且所有的分支结点的度都不为 1。

2.2 哈夫曼树构造算法实现

采用顺序存储结构--- 一维结构数组

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

  1. // 结点类型定义
  2. typedef struct{
  3. int weight;
  4. int parent,lch,rch;
  5. }HTNode,*HuffmanTree;
  6. // 找出森林中权值最小的两个
  7. void Select(HuffmanTree HT,int n,int &s1,int &s2) {
  8. int minum;
  9. int i;
  10. for(i=1;i<=n;i++){
  11. if(HT[i].parent == 0){
  12. minum = i;
  13. break;
  14. }
  15. }
  16. for(i = 1;i<=n;i++){
  17. if(HT[i].parent == 0){
  18. if(HT[i].weight<HT[minum].weight){
  19. minum = i;
  20. }
  21. }
  22. }
  23. s1 = minum;
  24. for(i=1;i<=n;i++){
  25. if(HT[i].parent == 0&& i!=s1){
  26. minum = i;
  27. break;
  28. }
  29. }
  30. for(i = 1;i<=n;i++){
  31. if(HT[i].parent == 0&& i!=s1){
  32. if(HT[minum].weight<HT[minum].weight){
  33. minum = i;
  34. }
  35. }
  36. }
  37. s2 = minum;
  38. }
  39. // 建立哈夫曼树
  40. void CreatHuffmanTree(HuffmanTree HT,int n){
  41. int m,i,s1,s2;
  42. if(n<=1){
  43. return ;
  44. }
  45. m = 2*n-1; // 数组共2n-1个元素
  46. HT = new HTNode[m+1]; // 0号单元未用,HT[m]表示根节点
  47. for(i=1;i<=m;i++){ // 将2n-1个元素的lch,rch,parent设置为0
  48. HT[i].lch = 0;
  49. HT[i].rch = 0;
  50. HT[i].parent = 0;
  51. }
  52. for(i = 1;i<=n;i++){ // 输入前n个元素的weight值
  53. scanf("%d",HT[i].weight);
  54. }
  55. // 初始化结束,下面开始建立哈夫曼树
  56. for(i=n+1;i<=m;i++){
  57. Select(HT,i-1,s1,s2);
  58. HT[s1].parent = i;
  59. HT[s2].parent = i;
  60. HT[i].lch = s1;
  61. HT[i].rch = s2;
  62. HT[i].weight = HT[s1].weight+HT[s2].weight;
  63. }
  64. }

3、哈夫曼编码

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

3.1 哈夫曼编码

  1. 统计字符集中每个字符在电文中出现的平均概率(概率越大,要求编码越短)

  2. 利用哈夫曼树的特点:权越大的叶子离根越近,将每个字符的概率值作为权重,构建哈夫曼树。则概率越大的结点,路径越短

  3. 在哈夫曼树的每个分支上标上0或1:

    • 结点的左分支标0,右分支标1

    • 把从根到每个叶子的路径上的标号连接起来,作为该叶子代表的字符的编码。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

 watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

  1. # include<stdio.h>
  2. # include<string.h>
  3. //存放哈夫曼编码
  4. typedef char** HuffmanCode;
  5. // 结点类型定义
  6. typedef struct{
  7. int weight;
  8. int parent,lch,rch;
  9. }HTNode,*HuffmanTree;
  10. // 哈夫曼编码
  11. void CreatHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n){
  12. HC = new char*[n+1];
  13. char *cd = new char[n];
  14. cd[n-1] = '\0';
  15. int start,c,f,i;
  16. for(i=1;i<=n;i++){
  17. start = n-1;
  18. c = i;
  19. f = HT[i].parent;
  20. while(f!=0){
  21. start--;
  22. if(HT[f].lch == c){
  23. cd[start] = '0';
  24. }else{
  25. cd[start] = '1';
  26. }
  27. c = f;
  28. f = HT[f].parent;
  29. }
  30. HC[i] = new char[n-start];
  31. strcpy(HC[i],&cd[start]);
  32. }
  33. delete cd; // 释放临时空间
  34. }

3.2 文件的编码和解码

        watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

 watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

 watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWFVOfk1MRg==,size_20,color_FFFFFF,t_70,g_se,x_16

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/595975
推荐阅读
相关标签
  

闽ICP备14008679号