数据结构|赫夫曼树及其应用|C语言

137 阅读3分钟

一、基本概念

  1. 结点的路径长度:从根结点到该结点的路径上分支的数目
  2. 树的路径长度:树中每个结点的路径长度之和
  3. 结点的带权路径长度:从根结点到该结点的路径长度(lk)与结点上权(wk)的乘积。
  4. 树的带权路径长度:树中所有叶子结点的带权路径长度之和,WPL(T) = Σwk·lk (对所有叶子结点)。

1712761456985.png

二、赫夫曼树(最优二叉树)

1.定义

在所有含 n 个叶子结点、并且叶子结点带相同权值的二叉树中,其带权路径长度WPL最小的那棵二叉树称为最优二叉树。

2.构造最优二叉树——赫夫曼算法

采用贪心策略。组成树的每个结点作为一棵树,从中选取权值为最小和次小的两个,分别作为左、右子树构造一棵新的二叉树,并置这棵新的二叉树根结点的权值为其左、右子树根结点的权值之和;从所有树中中删去这两棵树,同时加入刚生成的新树。重复选取根结点权值最小的两个,直至 F 中只含一棵树为止(重复 n-1次)。

  • n个叶子结点的赫夫曼树共有2n-1个结点
  • 赫夫曼树中没有度为1的结点,结点总数为n0+n2

3.赫夫曼编码

  1. 前缀编码:任何一个字符的编码都不是同一字符集中另一个字符的编码的前缀。
  2. 利用赫夫曼树可以构造一种不等长的二进制编码,并且构造所得的赫夫曼编码是一种最优前缀编码,即使所传电文的总长度最短
  3. 码文长度=Σ(每个字符编码长度*lk出现频次wk)

1712762286998.png

typedef struct {
	int weight;//权值
	int parent, lchild, rchild;//三个指针 
}HTNode, *HuffmanCode;//哈夫曼树
Typedef char **HuffmanCode;//哈夫曼码

void huffmancodeing(HuffmanTree &HT, HuffmanCode &HC, int *w, int n) {
	if(n < 1) return;//n为给定的权值的数量,所以结点总数为2n-1
	HT = (Huffman Tree)malloc((m+1)*sizeof(HTNode));//0号单元未用 
	for(p = HT + 1, i = 1; i <= n; ++p, ++w) *p = {*w, 0, 0, 0};
	for(; i <= m; ++i, ++p) *p = {0,0,0,0};
	for(i = n + 1 ;i <= m; ++i) {//生共成m-n个新树 
		Select(HT, i-1, s1, s2);//从n个叶结点里选两个权值最小的 
		HT[s1].parent = i;//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 *));
	 cd = (char *)malloc(n*sizeof(char));
	 cd[n-1] = "\0";//编码结束符
	 int start;
	 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[f].lchild == c)
				cd[--start] = "0";
				else cd[--start] = "1";
		HC[i] = (char *)malloc((n-start)*sizeof(char));
		strcpy(HC[i], &cd[start]);
		} 
	 free(cd);
	 } 
}