哈夫曼树及其应用

本文介绍了哈夫曼树的基本概念,包括结点路径、路径长度、带权路径长度等。接着详细阐述了如何构造哈夫曼树,遵循权值越大叶节点越靠近根结点的原则。哈夫曼编码是一种前缀编码,通过哈夫曼树的左分支为0,右分支为1来确定字符编码。最后讨论了Huffman编码算法的实现,包括结点结构和编码表的存储方式。
摘要由CSDN通过智能技术生成

1. 基本概念

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

② 路径长度:结点路径上的分支数目称为路径长度。

③ 树的路径长度:从树根到每一个结点的路径长度之和。

④ 结点的带权路径长度:从该结点的到树的根结点 之间的路径长度与结点的权(值)的乘积。

⑤ 树的带权路径长度:树中所有叶子结点的带权路径长度之和,记做: WPL=w1 × l1+w2 × l2+ ⋯ +wn × ln=∑wi×li (i=1,2,⋯,n) 其中:n为叶子结点的个数;wi为第i个结点的权 值; li为第i个结点的路径长度。

⑥ Huffman树:具有n个叶子结点(每个结点的权值为wi) 的二叉树不止一棵,但在所有的这些二叉树中,必定存在一棵具有最小带权路径长度的二叉树,称这棵树为 Huffman树(或称最优树) 。

2.Huffman树的构造

构造哈夫曼树的原则:

  • 权值越大的叶结点越靠近根结点;
  • 权值越小的叶结点越远离根结点。

构造哈夫曼树的过程:

(1)给定的n个权值{W1,W2,…,Wn }构造n棵只有一个叶节点的二叉树, 从而得到一个二叉树的集合F={T1,T2,…,Tn }。

(2)在F中选取根节点的权值最小和次小的两棵二叉树作为左、右子树 构造一棵新的二叉树,这棵新的二叉树根节点的权值为其左、右子树根节点权值之和。

(3)在集合F中删除作为左、右子树的两棵二叉树,并将新建立的二叉 树加入到集合F中。

(4)重复(2)、(3)两步,当F中只剩下一棵二叉树时,这棵二叉树便是所要建立的哈夫曼树。

过程图如下:

 

哈夫曼树的特点:n1=0,所以:

n = n0+n1+n2

   = n0+n2

   = 2 n0 -1

3. 哈夫曼编码及其算法

3.1 Huffman编码

①前缀编码:要设计长短不等的编码,还必须保证任意字符的编码都不是另一个字符编码的前缀,这种编码称为前缀编码。

②Huffman编码方法:规定哈夫曼树中的左分支为0,右分支为1,则从根节点到每个叶节点所经过的分支对应的0和1组成的序列便为该节点对应字符的编码。这样的编码称为哈夫曼编码。

③哈夫曼编码特点:权值越大的字符编码越短,反之越长。

3.2 Huffman编码算法实现

Huffman树和Huffman编码的存储实现

typedef  struct{

   unsigned  int weight;

   unsigned  int parent,lchild,rchild;

}HTNode, * HuffmanTree;                 //动态分配数组存储Huffman树

typedef  char  ** HuffmanCode;       //动态分配数组存储Huffman编码表

结点结构示意图:

weightparentlchildrchild

      其中: weight:权值域; parent:双亲结点下标 ;  lchild,rchild:分别标识左、右子树的下标。

 

② 算法实现

void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n)
  // w 存放 n 个字符的权值(均 > 0),构造哈夫曼树 HT,并求出 n 个字符的哈夫曼编码 HC.
  if ( n <= 1) return ;
  m = 2 * n - 1;
  HT = (HuffmanTree) malloc ((m + 1) * sizeof (HTNode));   //0号单元未用
  for(p = HT,i = 1; i <= n; ++i,++p,++w)
	*p = { *w,0,0,0 };
  for( ; i <= m; ++i)
    *p = { 0,0,0,0 };
  for( i = n+1; i <= m; ++i){   //建哈夫曼树
	  //在HT[i..i-1] 选择parent 为 0 且weight 最小的两个结点,其序号分别为 s1 和 s2.
	Select( HT, i-1, s1, s2);
	 HT[s1].parent = i;
	 HT[s2].parent = i;
	 HT[i].lchild = s1;
	 HT[i].rchild = s2;
	 HT[i].weight = HT[s1].weight + HT[s2].weight;
 }
 //从叶子到根逆向求每个字符的哈夫曼编码
 HC = (HuffmanCode) malloc ((n + 1) * sizeof (char *));  //分配 n 个字符编码的头指针向量
 cd = (char *) malloc ( n * sizeof(char));  //分配求编码的工作空间
 cd[ n-1 ] = "\0";        //编码结束符
 for(i = 1; i <= n; i++)   //逐个字符求哈夫曼编码
 {
	start = n - 1;         //编码结束符位置
	for(c = i,f = HT[i].parent; f != 0; c = f,f = HT[f].parent) //从叶子到根逆向求码
	    if( HT[i].lchild == c)
	       cd[--start] = "0";
	    else 
	       cd[--start] = "1";
	    HC[i] = (char *) malloc ((n -start) * sizeof (char)); //为第 i 个字符编码分配空间
	    strcpy(HC[i], &cd[start]);       //从 cd 复制编码到 HC
	}
	free(cd);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值