<数据结构>XDOJ261.理解哈夫曼树
问题与解答
问题描述:
假设用于通信的电文由 n(2≤n≤30)个字符组成,字符在电文中出现的频度(权值)为 w1 w2… wn,根据该权值集合构造哈夫曼树,并计算该树的带权路径长度。
输入说明:
输入分为两行。第 1 行为 n 的值,第 2 行为 n 个整数(数值不超过 100),表示每个字符在电文中的频度。
整数之间以空格或换行符间隔。
输出说明:
输出一个整数,表示所构造哈夫曼树的带权路径长度,换行。
测试样例:
输入样例 1
5
4 5 2 10 8
输出样例 1
64
/*哈夫曼树的理解*/
#include<stdio.h>
#include<algorithm>
using namespace std;
int main()
{
int n, A[30],i,sum=0;
scanf("%d", &n);
for(i = 0; i < n; i++)
scanf("%d", &A[i]);
sort(A, A+n); //从小到大排序找出最小的两个结点
for(i=1; i <= n-1; i++)
{
A[i] = A[i]+A[i-1]; //构造结点
sum += A[i]; //构造的结点求和即可得出最短带权路径
sort(A+i-1, A+n); //将构造的结点重新加入数组等待下次比较
}
printf("%d",sum);
}
题后反思:非必要实现
一开始想要直接实现哈夫曼树,直接模拟题目过程。后来转念一想发现没有必要直接实现哈夫曼树,只要用数组排序就可以模拟实现求解带权路径长度的过程。
哈夫曼树
定义
- 带权路径和最小的树(最优二叉树)
- 带权路径和的两种计算方法
- 定义计算
- 构造的结点求和
算法实现
- 基本算法: 把结点按权值排序,选权值较小的两个结点合成一个新结点,然后重复上述操作,最终得到的树就是哈夫曼树。
- 核心问题:如何找到权值最小的两个结点---利用最小堆!!!
- 伪码实现
typedef struct TreeNode *HuffmanTree;
struct TreeNode
{
int Weight;
HuffumanTree Left, Right;
};
HuffumanTree Huffuman(MinHeap H)
{
/* 假设H->Size个权值已经按照最小堆的顺序存放在 MInHeap里 */
int i; HuffumanTree T;
/* 做H->Size - 1 次合并 */
for(i = 0; i < H->Size-1; i++)
{
T = malloc(sizeof(struct HuffumanTree));
T->Left = Delete(H);
/* 从最小堆中删除一个结点,作为新T的左子节点 */
T->Right = Delete(H);
/* 从最小堆中删除一个结点,作为新T的右子节点 */
T->Weight = T->Left->Weight + T->Right->Weight;
/* 重新计算权值 */
Insert(T, H);
/* 将新T插入最小堆 */
}
T = Delete(H);
return T;
}
- 时间复杂度O(lgN)