练习做一下构造最优二叉树的算法,不过如何计算WPL呢?
本次未能实现,希望懂的人可以帮我解决一下这个问题,不胜感激!
//
// 头文件:HuffmanTree.h
//
// 叶子结点的最大数量
#define LEAVES_COUNT 4
//
// 二叉树的最大结点总数
#define NODES_COUNT (2 * LEAVES_COUNT - 1)
//
// 哈夫曼树的结点结构体
typedef struct tagHuffmanTreeNode
{
float weight; // 权值,假设权值都是大于零的值
int parent; // 指示双亲
int lchild; // 指示左孩子
int rchild; // 指示右孩子
}HuffmanNode;
//
// 哈夫曼树定义为二维数组
typedef HuffmanNode HuffmanTree[NODES_COUNT];
//
// 构造一棵哈夫曼树
void CreateHuffmanTree(HuffmanTree tree);
//
// 初始化
void InitHuffmanTree(HuffmanTree tree);
//
// 输入叶子的权值
void InputWeightsOfLeaves(HuffmanTree tree);
//
// 选择两个权最小的结点生成新的结点
void SelectMin(HuffmanTree tree, int maxValue, int *left, int *right);
//
// 计算哈夫曼树的最小带权路径长度之和
int ComputeWPL(HuffmanTree tree);
//
// 测试哈夫曼树的构造,译码
// HuffmanTree.c
#include <stdio.h>
#include <stdlib.h>
#include "HuffmanTree.h"
int main()
{
HuffmanTree tree;
// 构造哈夫曼树
CreateHuffmanTree(tree);
printf("WPL=%d\n", ComputeWPL(tree));
return 0;
}
//
// 构造一棵哈夫曼树
void CreateHuffmanTree(HuffmanTree tree)
{
int i;
int left, right;
InitHuffmanTree(tree); // 初始化
printf("输入%d个结点值:\n", LEAVES_COUNT);
InputWeightsOfLeaves(tree); // 输入叶子权值至T[0..n-1]的weight域
// 共进行n-1次合并,新结点依次存于T[i]中
for (i = LEAVES_COUNT; i < NODES_COUNT; i++)
{
// 在tree中0~i-1中选择最小的两个根结点
SelectMin(tree, i - 1, &left, &right);
// 在i个结点作为新合成结点的双亲
tree[left].parent = i;
tree[right].parent = i;
tree[i].lchild = left; // 最小权的根结点是新结点的左孩子
tree[i].rchild = right; // 次小权的根结点是新结点的右孩子
// 新结点的权值
tree[i].weight = tree[left].weight + tree[right].weight;
}
}
//
// 初始化
// 因为C语言数组的下界为0,故用-1表示空指针。树中某结点的lchild、rchild和parent不等于-1时,
// 它们分别是该结点的左、右孩子和双亲结点在向量中的下标。这里设置parent域有两个作用:其一是使查找
// 某结点的双亲变得简单;其二是可通过判定parent的值是否为-1来区分根与非根结点。
// 将T[0..m-1]中2n-1个结点里的三个指针均置为空(即置为-1),权值置为0。
void InitHuffmanTree(HuffmanTree tree)
{
int i = 0;
for (i = 0; i < NODES_COUNT; i++)
{
tree[i].lchild = -1;
tree[i].rchild = -1;
tree[i].parent = -1;
tree[i].weight = 0;
}
}
//
// 输入叶子的权值
// 读人n个叶子的权值存于向量的前n个分量(即T[0..n-1])中。它们是初始森林中n个孤立的根结点上的权值。
void InputWeightsOfLeaves(HuffmanTree tree)
{
char ch;
int i;
for (i = 0; i < LEAVES_COUNT; i++)
{
scanf("%c", &tree[i].weight);
}
}
//
// 选择两个权最小的结点生成新的结点
void SelectMin(HuffmanTree tree, int maxValue, int *left, int *right)
{
int i, j;
int const MAX_VALUE = 10000;
int m1, m2;
for (i = 0; i < maxValue; i++)
{
m1 = m2 = MAX_VALUE;
*left = 0;
*right = 0;
for (j = 0; j < LEAVES_COUNT + 1; j++)
{
if (tree[j].weight < m1 && tree[i].parent == -1) // 要求此结点还没有构造
{
m2 = m1; // 较大者给m2
*right = *left;
m1 = tree[j].weight; // 取较小者
*left = j;
}
else if (tree[j].weight < m2 && tree[i].parent == -1)
{
m2 = tree[j].weight;
*right = j;
}
}
}
}
//
// 计算哈夫曼树的最小带权路径长度之和
int ComputeWPL(HuffmanTree tree)
{
int i = 0;
int wpl = 0;
for (i = 0; i < NODES_COUNT; i++)
{
if (IsLeaf(tree[i]))
{
wpl += tree[i].weight * (i + 1); // 这里不正确,该如何获取结点所有的层数呢?
}
}
return wpl;
}
//
// 判断是否为叶子结点
int IsLeaf(HuffmanNode node)
{
return node.lchild == -1 && node.rchild == -1;
}