1.问题定义
修理牧场
2.问题分析
农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要 n 块木头,每块木头长度为整数 li 个长度单位,于是他购买了一条很长的、能锯成 n 块的木头,即该木头的长度是 li 的总和。请人锯木头的酬金跟这段木头的长度成正比,设酬金等于所锯木头的长度。
这可以化简成一个二叉树的问题,要想酬金最少,就要通过哈夫曼算法构建最优二叉树。根据哈夫曼树的定义,一棵二叉树要使带权路径长度最小,必须使权值越大的叶子结点越靠近根结点,而权值越小的叶子结点越远离根结点,而且不存在度为1的点。
3.概要设计
首先需要定义一个类来存储每个结点的信息,本题需要存储的是每个结点的权值,父母,左孩子和右孩子。
template <class C>
struct ElemNode
{
int weight;//结点权值
int parent, lchild, rchild;//游标
};
其次是建立哈夫曼树的类,其中包括构造函数,析构函数,Select函数(查找两个权值最小的结点),Sum函数(计算最小费用)
template <class C>
class HuffmanTree
{
public:
HuffmanTree(int a[], int n);
~HuffmanTree();
void Sum();
private:
C* huffTree;//存储各结点信息
int num;//存储结点个数
void Select(int n, int& i1, int& i2);
};
Select函数的思路是保持存储结点数据的原数组不动,通过引用变量来比较找出权值最小的两个结点。
template <class C>
void HuffmanTree<C>::Select(int n, int& i1, int& i2)//选取两个权值最小的结点
{
int i = 0, temp;
for (i=0; i < n; i++)
if (huffTree[i].parent == -1) { i1 = i; break; }
for (i = i + 1; i < n; i++)
if (huffTree[i].parent == -1) { i2 = i; break; }
if (huffTree[i1].weight > huffTree[i2].weight)
{
temp = i1; i1 = i2; i2 = temp;
}
for (i = i + 1; i < n; i++)
{
if (huffTree[i].parent == -1)
{
if (huffTree[i].weight < huffTree[i1].weight)
{
i2 = i1; i1 = i;
}
else if (huffTree[i].weight < huffTree[i2].weight)
{
i2 = i;
}
}
}
}
构造函数先给所有叶子结点初始化,无双亲和两个孩子,并输入各叶子结点权值。然后运用Select函数,选取最小的两个子结点获得其双亲结点作为数组新结点,进行n-次合并成一棵哈夫曼树。
template <class C>
HuffmanTree<C>::HuffmanTree(int a[], int n)//构造函数
{
int i, k, i1, i2;
huffTree = new C[2 * n - 1];//动态数组存储信息
num = n;
for (i = 0; i < 2 * num - 1; i++) //初始化,所有结点均没有双亲和孩子
{
huffTree[i].parent = -1;
huffTree[i].lchild = huffTree[i].rchild = -1;
}
for (i = 0; i < num; i++) //存储叶子结点的权值
huffTree[i].weight = a[i];
for (k = num; k < 2 * num - 1; k++) //n-1次合并
{
Select(k, i1, i2); //权值最小的根结点下标为i1和i2
huffTree[k].weight = huffTree[i1].weight + huffTree[i2].weight;
huffTree[i1].parent = k; huffTree[i2].parent = k;
huffTree[k].lchild = i1; huffTree[k].rchild = i2;
}
}
Sum函数较为简单,仅需遍历数组,找到所有有左孩子和右孩子的结点,将权值加到一起,便能得到最小酬金。
template <class C>
void HuffmanTree<C>::Sum()
{
int sum = 0;
for (int i = 0; i < 2 * num - 1; i++)
{
if (huffTree[i].lchild != -1 && huffTree[i].rchild != -1)
{
sum += huffTree[i].weight;
}
cout << sum << endl;
}
}
通过上述代码便可以通过给定切的木头块数以及各木块长度来求得最小金额。

1291

被折叠的 条评论
为什么被折叠?



