# 哈夫曼树

1. 定义
1、路径:从树中一个结点到另一个结点之间的分支构成两个结点之间的路径。
2、路径长度:路径的上分支的数目。
3、结点的路径长度:从根到该结点的路径长度。
4、树的路径长度:从树根到每一个结点的路径长度之和。
5、结点的权:在一些应用中,赋予树中结点的一个有某种意义实数。
6、结点的带权路径长度:从根结点到各个叶结点的路径长度与相应结点权值的乘积。
7、树的带权路径长度:所有叶结点的带权路径长度之和。
8、最优二叉树 / 赫夫曼树: 假设有 n 个权值 (w1,w2…wn),试构造一棵有 n 个叶子结点的二叉树,每个叶子结点带权为 wi ,则其中带权路径长度 WPL 最小的二叉树称作最优二叉树或赫夫曼树。

2. 存储结构
对于有 n 个叶子结点的赫夫曼树,结点总数为 2n-1 个,为实现方便,将叶子结点集 中存储在前面部分 1~n 个位置,而后面的 n-1 个位置中存储其余非叶子结点。
静态三叉链表中:weight|parent|LChild|RChild

// 用静态三叉链表实现的哈夫曼树类型定义如下:
#define N 20 /* 叶子结点的最大值。*/
#define M 2*N-1 /* 所有结点的最大值。*/
typedef struct{
	int weight ; /* 结点的权值 */
    int parent ; /* 双亲的下标 */
	int LChild ; /* 左孩子结点的下标 */
	int RChild ; /* 右孩子结点的下标 */
} HTNode, HuffmanTree[M+1]; 
/* HuffmanTree 是一个结构数组类型,0 号单元不用。 */

3. 算法实现

/* 构造哈夫曼树 ht [M+1], w [ ] 存放 n 个权值。*/
void CrtHuffmanTree(HuffmanTree ht, int w[ ], int n){ 
	for(i=1;i<=n;i++) ht[i] ={ w[i],0,0,0}; /* 1 ~ n 号单元存放叶子结点,初始化 */
	m=2*n-1;
	for(i=n+1;i<=m;i++) ht[i] ={0,0,0,0}; /* n+1 ~ m 号单元存放非叶结点,初始化 */
	/* 创建非叶结点,建哈夫曼树 */
	for(i=n+1; i<=m; i++){ 
// 在 ht [1] ~ ht [i-1] 的范围内选择两个 parent 为 0 且 weight 最小的结点,其序号分别赋值给 s1、s2 返回 
		select(ht, i-1, s1, s2); 
		ht [i].weight= ht [s1].weight+ ht [s2].weight;
		ht [s1].parent=i;
        ht [s2].parent=i;
		ht [i].LChild=s1;
        ht [i].RChild=s2;
	} /* 哈夫曼树建立完毕 */
}

# 哈夫曼编码

1. 概念

1. 前缀码:
如果在一个编码系统中,任一个编码都不是其他任何编码的前缀 (最左子串),则称该编码系统中的编码是前缀码。
2. 哈夫曼编码:对一棵具有 n 个叶子的哈夫曼树,若对树中的每个左分支赋予 0, 右分支赋予 1 (也可规定左 1 右 0),则从根到每个叶子的通路上,各分支的赋值分别构成一 个二进制串,该二进制串就称为哈夫曼编码。

2. 算法实现

typedef char * HuffmanCode[N+1]; /* 存储哈夫曼编码串的头指针数组 */
/* 从叶子结点到根,逆向求每个叶子结点对应的哈夫曼编码 */
void CrtHuffmanCode(HuffmanTree ht, HuffmanCode hc, int n){
	char *cd;
	cd=(char * )malloc(n* sizeof(char ));	/* 分配求当前编码的工作空间 */
	cd[n-1]=’\0;							/* 从右向左逐位存放编码,首先存放编码结束符 */
    
    /* 求 n 个叶子结点对应的哈夫曼编码 */
	for(i=1;i<=n;i++){ 
		start=n-1; 							/* 初始化编码起始指针 */
		c=i;
        p=ht[i].parent; 				/* 从叶子结点开始向上倒推 */
		while(p!=0){ 
            //start;
			if(ht[p].LChild==c) cd[start]=0; /* 左分支标 0*/
			else cd[start]=1; 			/* 右分支标 1*/
			c=p; p=ht[p].parent; 			/* 向上倒推 */
		}
		hc [i]=(char *)malloc((n-start)*sizeof(char)); /* 为第 i 个编码分配空间 */
		strcpy(hc[i], &cd[start]);					 /* 把编码复制到 hc [i] 中 */
	}
	free(cd);
}
-->