数据结构之哈夫曼树

五、哈夫曼树

1、哈夫曼树

哈夫曼(Huffma)树又称最优二叉树。它是n个带权叶子结点构成的所有二叉树中,带权路径长度WTL最小的二叉树。因为构造这种树的算法是最早由哈夫曼于1952年提出的,所以被称为哈夫曼树,相应的算法称为哈夫曼算法。

从树中某一结点到另一个节点所经过的分支构成这两个节点之间的路径。路径的分支数目叫做这两个节点之间的路径长度。

树的路径长度是从树根到树中每个结点之间路径长度之和。这种路径长度最短的是完全二叉树。

从根结点到某结点之间的路径长度与该结点所带的权值的乘积,称为该结点的带权路径长度,计作WkLk,其中Lk为结点K的路径长度,Wk为结点K的权值。

树的带权路径长度是树中所有带权结点的路径长度之和。

2、构造哈夫曼树

如何构造一棵带权路径长度最短的哈夫曼二叉树哈夫曼提出了如下算法:(1)根据n个权值{w1,w2,…,wn}构成n棵二叉树的森林T={T1,T2,…,Tn},其中Ti只有一个带权为 wi的根结点,且左右子树均为空。
(2)在T中选取两棵根结点的权值最小的树作为左右子树,构造一棵新的二叉树,且置新的二叉树的根结点的权值为其左右子树上根结点的权值之和。
(3)在T中删除这两棵树,同时将新得到的二叉树加入森林中。
(4)重复(2)和(3),直到森林中只有一棵树为止,这棵树即为哈夫曼树。

3、哈夫曼树的构造算法描述如下:

# include "stdio.h"
# include "stdlib.h"
# include "alloc.h"
#define m 100
struct ptree // 定义二叉树结点类型
{ int w; //定义结点权值
  struct ptree * lchild; //定义左子结点指针
  struct ptree * rchild; //定义右子结点指针
};
struct pforest // 定义链表结点类型
{ struct pforest * link; 
  struct ptree * root; 
}; 
int WTL=0; //初始化WTL为0
main( ) 
{
  struct ptree * hafm( ); 
  void travel( ); 
  struct ptree * head; 
  int n,i,w[m]; 
  printf ("please input the sum of node \ n"); //提示输入结点数
  scanf ("%d", &n); //输入结点数
  printf ("please input weight of every node \ n"); //提示输入每个结点的权值
  for (i=1;i<=n;i++)
    scanf ("%d", &w[i]); //输入每个节点权值
  head=hafm(w,n); 
  travel (head, 0); 
  printf ("The length of the best path is WTL=%d", WTL); //输出最佳路径权值之和
}
void travel (head, n) //为了验证harfm算法的正确性进行的遍历
struct ptree * head; 
int n; 
{
  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); 
         WTL=WTL+n* (p->w); //计算权值
       }
      travel (p->lchild, n+1); 
      travel (p->rchild, n+1); 
   }
}
struct ptree * hafm (w, n) 
int n; 
int w[m]; 
{
  struct pforest * inforest ( ); 
  struct pforest * p1, * p2, * f; 
  struct ptree * ti, * t, * t1, * t2; 
  int i; 
  f=(struct pfores * )malloc(sizeof(struct pforest)); 
  f->link=NULL; 
  for (i=1;i<=n;i++) // 产生n棵只有根结点的二叉树
  {
    ti= (struct ptree *)malloc(sizeof(struct ptree)); //开辟新的结点空间
    ti->w=w[i]; //给结点赋权值
    ti->lchild=NULL; 
    ti->rchild=NULL; 
    f=inforest (f, ti); 
   }
   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=(struct ptree *)malloc (sizeof(struct ptree)); //开辟新的结点空间
     t->w=t1->w+t2->w; // 权相加
     t->lchild=t1;  
     t->rchild=t2; // 产生新二叉树
     f=inforest (f, t);
    }
   p1=f->link;
   t=p1->root; 
   return(t); //返回t
}
struct pforest * inforest (f, t)
struct pforest * f;
sturct ptree * t;
{
  struct pforest * p, * q, * r;
  struct ptree * ti;
  r=(struct pforest *) malloc(sizeof(struct 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向后寻找

}
else
p=NULL; // 强迫退出循环

}

r->link=q->link;

q->link=r; //r接在q的后面

return (f); //返回f

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
哈夫曼树是一种二叉树,它的叶子节点代表着一组数据,而非叶子节点代表着数据的组合。哈夫曼树的构建是基于数据的出现频率来进行的,出现频率高的数据在哈夫曼树中的深度较浅,而出现频率低的数据在哈夫曼树中的深度较深。因此,哈夫曼树可以用来实现数据的压缩和加密。 哈夫曼树的构建步骤如下: 1. 将数据按照出现频率从小到大排序。 2. 选取出现频率最小的两个数据,构建一个新的二叉树,其中这两个数据分别作为左右子树的叶子节点,并将这个新的二叉树的根节点的权值设置为这两个数据的权值之和。 3. 将这个新的二叉树插入到已有的二叉树集合中,保持集合按照权值从小到大排序。 4. 重复步骤2和步骤3,直到所有的数据都被构建成了二叉树。 5. 最后得到的二叉树就是哈夫曼树。 下面是一个Python实现的例子: ```python class Node: def __init__(self, value, freq): self.value = value self.freq = freq self.left = None self.right = None def huffman_tree(data): nodes = [Node(value, freq) for value, freq in data.items()] while len(nodes) > 1: nodes = sorted(nodes, key=lambda x: x.freq) left_node = nodes.pop(0) right_node = nodes.pop(0) new_node = Node(None, left_node.freq + right_node.freq) new_node.left = left_node new_node.right = right_node nodes.append(new_node) return nodes[0] data = {'a': 5, 'b': 9, 'c': 12, 'd': 13, 'e': 16, 'f': 45} root = huffman_tree(data) ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值