最优二叉树——哈夫曼树

最优二叉树——哈夫曼树最优二叉树 哈夫曼树标签 structnull 算法 inputpathtre 04 2818 0 人阅读评论 11 收藏举报分类 学习专区 140 作者同类文章 X 数据结构 1 作者同类文章 X 版权声明 本文为博主原创文章 未经博

最优二叉树——哈夫曼树

标签: structnull算法inputpathtree

22303人阅读
评论(11)
收藏
举报

最优二叉树——哈夫曼树 分类:

作者同类文章
X

    作者同类文章
    X


       

      一:什么是最优二叉树?

      从我个人理解来说,最优二叉树就是从已给出的目标带权结点(单独的结点) 经过一种方式的组合形成一棵树.使树的权值最小. 最优二叉树是带权路径长度最短的二叉树。根据结点的个数,权值的不同,最优二叉树的形状也各不相同。它们的共同点是:带权值的结点都是叶子结点。权值越小的结点,其到根结点的路径越长

      官方定义:

      在权为wl,w2,…,wn的n个叶子所构成的所有二叉树中,带权路径长度最小(即代价最小)的二叉树称为最优二叉树哈夫曼树

      二:下面先弄清几个几个概念:

      1.路径长度

      在树中从一个结点到另一个结点所经历的分支构成了这两个结点间的路径上的分支数称为它的路径长度

      2.树的路径长度
           树的路径长度是从树根到树中每一结点的路径长度之和。在结点数目相同的二叉树中,完全二叉树的路径长度最短。

      3.树的带权路径长度(Weighted Path Length of Tree,简记为WPL)
        结点的权

      :在一些应用中,赋予树中结点的一个有某种意义的实数。
        结点的带权路径长度:结点到树根之间的路径长度与该结点上权的乘积。
        树的带权路径长度(Weighted Path Length of Tree):定义为树中所有叶结点的带权路径长度之和,通常记为: 
                      
        其中:
       
















         n表示叶子结点的数目
          wi

      li分别表示叶结点ki的权值和根到结点ki之间的路径长度。
         

      树的带权路径长度亦称为树的代价。

      三:用一个例子来理解一下以上概念

      【例】给定4个叶子结点a,b,c和d,分别带权7,5,2和4。构造如下图所示的三棵二叉树(还有许多棵),它们的带权路径长度分别为:

      最优二叉树——哈夫曼树

              (a)WPL=7*2+5*2+2*2+4*2=36
              (b)WPL=7*3+5*3+2*1+4*2=46
              (c)WPL=7*1+5*2+2*3+4*3=35




      其中(c)树的WPL最小,可以验证,它就是哈夫曼树。

       

       

      注意:
          ① 叶子上的权值均相同时,完全二叉树一定是最优二叉树,否则完全二叉树不一定是最优二叉树。
          ② 最优二叉树中,权越大的叶子离根越近。
          ③ 最优二叉树的形态不唯一,WPL最小






       

      四.哈夫曼算法

      对于给定的叶子数目及其权值构造最优二叉树的方法,由于这个算法是哈夫曼提出来的,故称其为哈夫曼算法。其基本思想是:
        (1)根据给定的n个权值wl,w2,…,wn构成n棵二叉树的森林F={T1,T2,…,Tn},其中每棵二叉树Ti中都只有一个权值为wi的根结点,其左右子树均空。
        (2)在森林F中选出两棵根结点权值最小的树(当这样的树不止两棵树时,可以从中任选两棵),将这两棵树合并成一棵新树,为了保证新树仍是二叉树,需 要增加一个新结点作为新树的根,并将所选的两棵树的根分别作为新根的左右孩子(谁左,谁右无关紧要),将这两个孩子的权值之和作为新树根的权值。
        (3)对新的森林F重复(2),直到森林F中只剩下一棵树为止。这棵树便是哈夫曼树。 
       








      注意:
          ① 初始森林中的n棵二叉树,每棵树有一个孤立的结点,它们既是根,又是叶子
          ② n个叶子的哈夫曼树要经过n-1次合并,产生n-1个新结点。最终求得的哈夫曼树中共有2n-1个结点。
          ③ 哈夫曼树是严格的二叉树,没有度数为1的分支结点。






      五:最优二叉树算法具体实现思路

      在构造哈夫曼树时,可以设置一个结构数组HuffNode保存哈夫曼树中各结点的信息,根据二叉树的性质可知,具有n个叶子结点的哈夫曼树共有2n-1个结点,所以数组HuffNode的大小设置为2n-1,数组元素的结构形式如下:  

      weight

      lchild

      rchild

      parent

       

      其中,weight域保存结点的权值,lchild和rchild域分别保存该结点的左、右孩子结点在数组HuffNode中的序号,从而建立起结 点之间的关系。为了判定一个结点是否已加入到要建立的哈夫曼树中,可通过parent域的值来确定。初始时parent的值为-1,当结点加入到树中时, 该结点parent的值为其双亲结点在数组HuffNode中的序号,就不会是-1了。构造哈夫曼树时,首先将由n个字符形成的n个叶结点存放到数组HuffNode的前n个分量中,然后根据前面介绍的哈夫曼方法的基本思想,不断将两个小子树合并为一个较大的子树,每次构成的新子树的根结点顺序放到HuffNode数组中的前n个分量的后面。

      具体实现:

      1)存储结构


      1. “font-size:18px;”>#define n 100               
        //叶结点数目  
      2.   
      3. #define m 2*n-1             //树中结点总数  
      4.   
      5. typedef struct  
      6.   
      7. {  
      8.   
      9.        floatweight;             //权值,设权值均大于零  
      10.   
      11.        intlchild,rchild,parent;  //左右孩子及双亲指针  
      12.   
      13. } HTNode;  
      14.   
      15.  typedef HTNode HuffmanTree[m]; //哈夫曼树是一维数组  
      #define n 100 //叶结点数目 #define m 2*n-1 //树中结点总数 typedef struct { floatweight; //权值,设权值均大于零 intlchild,rchild,parent; //左右孩子及双亲指针 } HTNode; typedef HTNode HuffmanTree[m]; //哈夫曼树是一维数组


      (2)赫夫曼算法的数组法构造

      1. void CreateHuffmanTree(HuffmanTree T)    
      2.   
      3. {    
      4.   
      5.     int i,p1,p2;                        //构造哈夫曼树,T[m-1]为其根结点    
      6.   
      7.     InitHuffmanTree(T);       //T初始化    
      8.   
      9.     InputWeight(T);               //输入叶子权值至T[0..n-1]的weight域    
      10.   
      11.     for(i=n;i

      12.   
      13.     {      
      14.   
      15.          SelectMin(T,i-1,&p1,&p2);//共进行n-1次合并,新结点依次存于T[i]中    
      16.   
      17.                  //在T[0…i-1]中选择两个权最小的根结点,其序号分别为p1和p2    
      18.   
      19.         T[p1].parent=T[p2].parent=i;    
      20.   
      21.         T[i].1child=p1;              //最小权的根结点是新结点的左孩子    
      22.   
      23.         T[i].rchild=p2;               //次小权的根结点是新结点的右孩子    
      24.   
      25.         T[i].weight=T[p1].weight+T[p2].weight;    
      26.   
      27.     }//for    
      28.   
      29. }//CreateHuffman    
      void CreateHuffmanTree(HuffmanTree T) { int i,p1,p2; //构造哈夫曼树,T[m-1]为其根结点 InitHuffmanTree(T); //T初始化 InputWeight(T); //输入叶子权值至T[0..n-1]的weight域 for(i=n;i 
            

       

      C语言实现全部代码:

      1. #include “stdio.h”  
      2.   
      3. #include “stdlib.h”  
      4.   
      5. #define m 100  
      6.   
      7.    
      8.   
      9. struct ptree              //定义二叉树结点类型  
      10.   
      11. {  
      12.   
      13. int w;                   //定义结点权值  
      14.   
      15. struct ptree *lchild;     //定义左子结点指针  
      16.   
      17. struct ptree *rchild;     //定义右子结点指针  
      18.   
      19. };  
      20.   
      21.    
      22.   
      23. struct pforest              //定义链表结点类型  
      24.   
      25. {  
      26.   
      27. struct pforest *link;  
      28.   
      29. struct ptree *root;  
      30.   
      31. };  
      32.   
      33.    
      34.   
      35. int WPL=0;                  //初始化WTL为0  
      36.   
      37. struct ptree *hafm();  
      38.   
      39. void travel();  
      40.   
      41. struct pforest *inforest(struct pforest*f,struct ptree *t);  
      42.   
      43.    
      44.   
      45. void travel(struct ptree *head,int n)                      
      46.   
      47. {  
      48.   
      49. //为验证harfm算法的正确性进行的遍历  
      50.   
      51. struct ptree *p;  
      52.   
      53. p=head;  
      54.   
      55. if(p!=NULL)  
      56.   
      57.  {  
      58.   
      59.       if((p->lchild)==NULL && (p->rchild)==NULL) //如果是叶子结点  
      60.   
      61.      {  
      62.   
      63.              printf(“%d “,p->w);  
      64.   
      65.              printf(“the hops of the node is: %d/n”,n);  
      66.   
      67.       WPL=WPL+n*(p->w);    //计算权值  
      68.   
      69.         }//if  
      70.   
      71. travel(p->lchild,n+1);  
      72.   
      73. travel(p->rchild,n+1);  
      74.   
      75. }//if  
      76.   
      77. }//travel  
      78.   
      79.    
      80.   
      81. struct ptree *hafm(int n, int w[m])  
      82.   
      83. {  
      84.   
      85. struct pforest *p1,*p2,*f;  
      86.   
      87. struct ptree *ti,*t,*t1,*t2;  
      88.   
      89. int i;  
      90.   
      91. f=(pforest *)malloc(sizeof(pforest));  
      92.   
      93. f->link=NULL;  
      94.   
      95. for(i=1;i<=n;i++)          //产生n棵只有根结点的二叉树  
      96.   
      97.   {  
      98.   
      99.       ti=(ptree*)malloc(sizeof(ptree));//开辟新的结点空间  
      100.   
      101.    ti->w=w[i];               //给结点赋权值  
      102.   
      103.    ti->lchild=NULL;  
      104.   
      105.    ti->rchild=NULL;  
      106.   
      107.    f=inforest(f, ti);  
      108.   
      109.       //按权值从小到大的顺序将结点从上到下地挂在一颗树上       
      110.   
      111.  }//for  
      112.   
      113. while(((f->link)->link)!=NULL)//至少有二棵二叉树  
      114.   
      115.   {  
      116.   
      117.  p1=f->link;  
      118.   
      119.  p2=p1->link;  
      120.   
      121.  f->link=p2->link;           //取出前两棵树  
      122.   
      123.  t1=p1->root;  
      124.   
      125.  t2=p2->root;  
      126.   
      127.  free(p1);                 //释放p1  
      128.   
      129.  free(p2);                 //释放p2  
      130.   
      131.  t=(ptree *)malloc(sizeof(ptree));//开辟新的结点空间  
      132.   
      133.  t->w = (t1->w)+(t2->w);        //权相加  
      134.   
      135.  t->lchild=t1;  
      136.   
      137.  t->rchild=t2;             //产生新二叉树  
      138.   
      139.  f=inforest(f,t);  
      140.   
      141.  }//while  
      142.   
      143.  p1=f->link;  
      144.   
      145.  t=p1->root;  
      146.   
      147.  free(f);  
      148.   
      149.  return(t);                  //返回t  
      150.   
      151.  }  
      152.   
      153.    
      154.   
      155. pforest *inforest(struct pforest *f,structptree *t)  
      156.   
      157. {  
      158.   
      159. //按权值从小到大的顺序将结点从上到下地挂在一颗树上       
      160.   
      161. struct pforest *p, *q, *r;  
      162.   
      163. struct ptree *ti;  
      164.   
      165. r=(pforest *)malloc(sizeof(pforest)); //开辟新的结点空间  
      166.   
      167. r->root=t;  
      168.   
      169. q=f;  
      170.   
      171. p=f->link;               
      172.   
      173. while (p!=NULL)            //寻找插入位置  
      174.   
      175.  {  
      176.   
      177.   ti=p->root;  
      178.   
      179.   if(t->w > ti->w)         //如果t的权值大于ti的权值  
      180.   
      181.      {  
      182.   
      183.         q=p;  
      184.   
      185.      p=p->link;             //p向后寻找  
      186.   
      187.     }//if  
      188.   
      189.   else  
      190.   
      191.       p=NULL;                  //强迫退出循环  
      192.   
      193.  }//while  
      194.   
      195. r->link=q->link;  
      196.   
      197. q->link=r;                 //r接在q的后面  
      198.   
      199. return(f);                 //返回f  
      200.   
      201. }  
      202.   
      203.    
      204.   
      205. void InPut(int &n,int w[m])  
      206.   
      207. {  
      208.   
      209. printf(“please input the sum ofnode/n”); //提示输入结点数  
      210.   
      211. scanf(“%d”,&n);      //输入结点数  
      212.   
      213. printf (“please input weight of everynode/n”); //提示输入每个结点的权值  
      214.   
      215. for(int i=1;i<=n;i++)  
      216.   
      217. scanf(“%d”,&w[i]);  //输入每个结点权值  
      218.   
      219. }  
      220.   
      221.    
      222.   
      223. int main( )  
      224.   
      225. {  
      226.   
      227. struct ptree *head;  
      228.   
      229. int n,w[m];  
      230.   
      231. InPut(n,w);  
      232.   
      233. head=hafm(n,w);  
      234.   
      235. travel(head,0);  
      236.   
      237. printf(“The length of the best path isWPL=%d”, WPL);//输出最佳路径权值之和  
      238.   
      239. return 1;  
      240.   
      241. }  
      242.   
      243.    
      #include "stdio.h" #include "stdlib.h" #define m 100 struct ptree //定义二叉树结点类型 { int w; //定义结点权值 struct ptree *lchild; //定义左子结点指针 struct ptree *rchild; //定义右子结点指针 }; struct pforest //定义链表结点类型 { struct pforest *link; struct ptree *root; }; int WPL=0; //初始化WTL为0 struct ptree *hafm(); void travel(); struct pforest *inforest(struct pforest*f,struct ptree *t); void travel(struct ptree *head,int n) { //为验证harfm算法的正确性进行的遍历 struct ptree *p; p=head; if(p!=NULL) { if((p->lchild)==NULL && (p->rchild)==NULL) //如果是叶子结点 { printf("%d ",p->w); printf("the hops of the node is: %d/n",n); WPL=WPL+n*(p->w); //计算权值 }//if travel(p->lchild,n+1); travel(p->rchild,n+1); }//if }//travel struct ptree *hafm(int n, int w[m]) { struct pforest *p1,*p2,*f; struct ptree *ti,*t,*t1,*t2; int i; f=(pforest *)malloc(sizeof(pforest)); f->link=NULL; for(i=1;i<=n;i++) //产生n棵只有根结点的二叉树 { ti=(ptree*)malloc(sizeof(ptree));//开辟新的结点空间 ti->w=w[i]; //给结点赋权值 ti->lchild=NULL; ti->rchild=NULL; f=inforest(f, ti); //按权值从小到大的顺序将结点从上到下地挂在一颗树上 }//for while(((f->link)->link)!=NULL)//至少有二棵二叉树 { p1=f->link; p2=p1->link; f->link=p2->link; //取出前两棵树 t1=p1->root; t2=p2->root; free(p1); //释放p1 free(p2); //释放p2 t=(ptree *)malloc(sizeof(ptree));//开辟新的结点空间 t->w = (t1->w)+(t2->w); //权相加 t->lchild=t1; t->rchild=t2; //产生新二叉树 f=inforest(f,t); }//while p1=f->link; t=p1->root; free(f); return(t); //返回t } pforest *inforest(struct pforest *f,structptree *t) { //按权值从小到大的顺序将结点从上到下地挂在一颗树上 struct pforest *p, *q, *r; struct ptree *ti; r=(pforest *)malloc(sizeof(pforest)); //开辟新的结点空间 r->root=t; q=f; p=f->link; while (p!=NULL) //寻找插入位置 { ti=p->root; if(t->w > ti->w) //如果t的权值大于ti的权值 { q=p; p=p->link; //p向后寻找 }//if else p=NULL; //强迫退出循环 }//while r->link=q->link; q->link=r; //r接在q的后面 return(f); //返回f } void InPut(int &n,int w[m]) { printf("please input the sum ofnode/n"); //提示输入结点数 scanf("%d",&n); //输入结点数 printf ("please input weight of everynode/n"); //提示输入每个结点的权值 for(int i=1;i<=n;i++) scanf("%d",&w[i]); //输入每个结点权值 } int main( ) { struct ptree *head; int n,w[m]; InPut(n,w); head=hafm(n,w); travel(head,0); printf("The length of the best path isWPL=%d", WPL);//输出最佳路径权值之和 return 1; } 
















      10

      0
       
       
        相关文章推荐
      • 哈夫曼树
      • Hadoop生态系统零基础入门
      • Huffman算法(最优二叉树)
      • 系统集成工程师必过冲刺!
      • 哈夫曼树详解
      • 征服React Native我有妙招
      • 哈夫曼树的基本构建与操作
      • FFmpeg音视频高级开发实战
      • 多叉树
      • 5天搞定深度学习框架-Caffe
      • 数据结构实验报告《五、最优二叉树应用之哈夫曼编译码》
      • Python数据分析经典案例解析
      • 数据结构之哈夫曼树(最优二叉树)
      • 谭浩强C语言程序设计,C++程序设计,严蔚敏数据结构,高一凡数据结构算法分析与实现.rar
      • 哈夫曼树(最优二叉树)
      • 第五章 树与二叉树

      版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

      发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/211192.html原文链接:https://javaforall.net

      (0)
      上一篇 2026年3月18日 下午10:59
      下一篇 2026年3月18日 下午11:00


      相关推荐

      • 阿里图床api_阿里远程图床

        阿里图床api_阿里远程图床介绍:一款非常美观且极简响应式的阿里图床PHP源码服务器要求支持php修复了浏览器复制出错的bug网盘下载地址:http://kekewl.cc/3NvM8RdOWui0图片:

        2025年6月5日
        4
      • jenkins allure_Jenkins

        jenkins allure_Jenkins前言jenkins集成了allure插件,安装插件后运行pytest+allure的脚本即可在jenkins上查看allure报告了。allure安装在运行代码的服务器本机,我这里是用的dock

        2022年8月6日
        8
      • OpenClaw多环境管理:开发、测试、生产

        OpenClaw多环境管理:开发、测试、生产

        2026年3月14日
        1
      • VC编程入门浅谈「建议收藏」

        VC编程入门浅谈「建议收藏」
        学VC并不是传说的那么难,可不下些功夫是学不成的。学编程急不得,没有编程的基础知识上来就学VC肯定碰一头灰,说VC难就难在这点上了。如果硬上,意志坚强的话还能挺过来,但最后还得回头来补习基础知识。意志不坚强的话,很有可能就此放弃,并留下一个VC难得不得了的印象。

          其实,只要踏踏实实一步一步来,学VC很简单。对于没有编程基础的人首先要学习编程的基础知识,如变量,语句,基本的算法等,然后写一些小的程序,实现些常用算法对自己的思维是很好的锻炼,对以后的学习大有好处。起码要能排

        2022年6月17日
        33
      • 7月上旬国内网站流量统计TOP5:新浪跻身五强居四

        7月上旬国内网站流量统计TOP5:新浪跻身五强居四

        2021年9月7日
        78
      • 怎么生成pkl文件_python unzip

        怎么生成pkl文件_python unzip我在训练UCF101数据集的时候,遇到一个大高玩使用pkl文件,一开始使用它们的数据炮的好好的。后来开始跑自己的数据时,就出问题了。不知道这个pkl到底是个什么东西。原始的那个大高玩的ucf101的标签数据读取出来是这个样的:[‘PommelHorse’,’Surfing’,’HammerThrow’,’PlayingViolin’,’WallPushups’,’PullUps’,’PizzaTossing’,’SalsaSpin’,’Shotput’,’CricketShot’,

        2025年9月3日
        7

      发表回复

      您的邮箱地址不会被公开。 必填项已用 * 标注

      关注全栈程序员社区公众号