[英]Adding sum of frequencies whille solving Optimal Binary search tree
我指的是这个问题和解决方案。
首先,我不明白为什么将频率之和加到递归方程中。 有人可以帮忙理解一个例子。
用作者的话来说。
我们将i到j的频率总和相加(请参见上式中的第一项),这是因为每次搜索都将经过根,并且每次搜索都将进行一次比较。
在代码中,频率之和(我不了解其目的)...对应于fsum。
int optCost(int freq[], int i, int j)
{
// Base cases
if (j < i) // If there are no elements in this subarray
return 0;
if (j == i) // If there is one element in this subarray
return freq[i];
// Get sum of freq[i], freq[i+1], ... freq[j]
int fsum = sum(freq, i, j);
// Initialize minimum value
int min = INT_MAX;
// One by one consider all elements as root and recursively find cost
// of the BST, compare the cost with min and update min if needed
for (int r = i; r <= j; ++r)
{
int cost = optCost(freq, i, r-1) + optCost(freq, r+1, j);
if (cost < min)
min = cost;
}
// Return minimum value
return min + fsum;
}
其次,该解决方案将仅返回最佳成本。 关于如何获得实际bst有什么建议吗?
为什么我们需要频率总和
频率总和背后的想法是正确计算特定树的成本。 它的行为就像存储树重量的累加器值。
想象一下,在第一级递归中,我们从树的第一级上的所有键开始(我们尚未选择任何根元素)。 记住权重函数-它求和所有节点权重乘以节点级别。 现在,我们树的权重等于所有键的权重之和,因为我们的任何键都可以位于任何级别(从第一层开始),并且无论如何,我们在结果中每个键的权重至少为一个。
1)假设我们找到了最佳根密钥,即密钥r
。 接下来,我们将除r
以外的所有键向下移动一个级别,因为剩下的每个元素最多可以位于第二个级别上(第一级别已被占用)。 因此,我们将剩下的每个键的权重加到总和上,因为无论如何,对于所有这些键,我们将至少具有两倍的权重。 左边的键根据我们之前选择的r
元素(从r
到右边的左边)分成两个子数组。
2)下一步是选择第二级的最佳键,从第一步剩下的两个子阵列中的每个子阵列中选择一个。 之后,我们再次将所有按键向左下移一层,并将其权重添加到总和中,因为它们将至少位于第三层,因此每个按键的权重至少为三倍。
3)依此类推。
我希望这种解释能使您对为什么我们需要这种频率总和有所了解。
寻找最佳的BST
正如作者在文章末尾提到的
2)在上述解决方案中,我们仅计算了最佳成本。 可以轻松修改解决方案以存储BST的结构。 我们可以创建另一个大小为n的辅助数组来存储树的结构。 我们要做的就是将所选的“ r”存储在最里面的循环中。
我们可以做到这一点。 在下面,您将找到我的实现。
一些注意事项:
1)我被迫用实用程序类Matrix
替换int[n][n]
,因为我使用了Visual C ++,并且它不支持非编译时间常数表达式作为数组大小。
2)我使用了您提供的文章的第二种算法实现(带有记忆),因为添加功能来存储最佳bst要容易得多。
3)作者的代码有误: for (int i=0; i<=n-L+1; i++)
第二个循环的上限应为nL
而不是n-L+1
。
4)我们存储最佳bst的方式如下:对于每对i, j
我们存储最佳密钥索引。 这与最佳成本相同,但是我们存储最佳密钥索引而不是存储最佳成本。 例如,对于0, n-1
我们将得到结果树的根键r
的索引。 接下来,我们根据根元素索引r
将数组分为两部分,并获得其最佳键索引。 我们可以通过访问矩阵元素0, r-1
和r+1, n-1
。 依此类推。 实用程序功能“ PrintResultTree”使用此方法并按顺序(左子树,节点,右子树)打印结果树。 因此,您基本上会获得有序列表,因为它是二进制搜索树。
5)请不要为我的代码而发火-我实际上不是C ++程序员。 :)
int optimalSearchTree(int keys[], int freq[], int n, Matrix& optimalKeyIndexes)
{
/* Create an auxiliary 2D matrix to store results of subproblems */
Matrix cost(n,n);
optimalKeyIndexes = Matrix(n, n);
/* cost[i][j] = Optimal cost of binary search tree that can be
formed from keys[i] to keys[j].
cost[0][n-1] will store the resultant cost */
// For a single key, cost is equal to frequency of the key
for (int i = 0; i < n; i++)
cost.SetCell(i, i, freq[i]);
// Now we need to consider chains of length 2, 3, ... .
// L is chain length.
for (int L = 2; L <= n; L++)
{
// i is row number in cost[][]
for (int i = 0; i <= n - L; i++)
{
// Get column number j from row number i and chain length L
int j = i + L - 1;
cost.SetCell(i, j, INT_MAX);
// Try making all keys in interval keys[i..j] as root
for (int r = i; r <= j; r++)
{
// c = cost when keys[r] becomes root of this subtree
int c = ((r > i) ? cost.GetCell(i, r - 1) : 0) +
((r < j) ? cost.GetCell(r + 1, j) : 0) +
sum(freq, i, j);
if (c < cost.GetCell(i, j))
{
cost.SetCell(i, j, c);
optimalKeyIndexes.SetCell(i, j, r);
}
}
}
}
return cost.GetCell(0, n - 1);
}
以下是实用程序类Matrix
:
class Matrix
{
private:
int rowCount;
int columnCount;
std::vector<int> cells;
public:
Matrix()
{
}
Matrix(int rows, int columns)
{
rowCount = rows;
columnCount = columns;
cells = std::vector<int>(rows * columns);
}
int GetCell(int rowNum, int columnNum)
{
return cells[columnNum + rowNum * columnCount];
}
void SetCell(int rowNum, int columnNum, int value)
{
cells[columnNum + rowNum * columnCount] = value;
}
};
和具有实用程序功能的主要方法按顺序打印结果树:
//Print result tree in in-order
void PrintResultTree(
Matrix& optimalKeyIndexes,
int startIndex,
int endIndex,
int* keys)
{
if (startIndex == endIndex)
{
printf("%d\n", keys[startIndex]);
return;
}
else if (startIndex > endIndex)
{
return;
}
int currentOptimalKeyIndex = optimalKeyIndexes.GetCell(startIndex, endIndex);
PrintResultTree(optimalKeyIndexes, startIndex, currentOptimalKeyIndex - 1, keys);
printf("%d\n", keys[currentOptimalKeyIndex]);
PrintResultTree(optimalKeyIndexes, currentOptimalKeyIndex + 1, endIndex, keys);
}
int main(int argc, char* argv[])
{
int keys[] = { 10, 12, 20 };
int freq[] = { 34, 8, 50 };
int n = sizeof(keys) / sizeof(keys[0]);
Matrix optimalKeyIndexes;
printf("Cost of Optimal BST is %d \n", optimalSearchTree(keys, freq, n, optimalKeyIndexes));
PrintResultTree(optimalKeyIndexes, 0, n - 1, keys);
return 0;
}
编辑:
在下面,您可以找到创建简单树状结构的代码。
这是实用程序TreeNode
类
struct TreeNode
{
public:
int Key;
TreeNode* Left;
TreeNode* Right;
};
使用BuildResultTree
函数更新了main
函数
void BuildResultTree(Matrix& optimalKeyIndexes,
int startIndex,
int endIndex,
int* keys,
TreeNode*& tree)
{
if (startIndex > endIndex)
{
return;
}
tree = new TreeNode();
tree->Left = NULL;
tree->Right = NULL;
if (startIndex == endIndex)
{
tree->Key = keys[startIndex];
return;
}
int currentOptimalKeyIndex = optimalKeyIndexes.GetCell(startIndex, endIndex);
tree->Key = keys[currentOptimalKeyIndex];
BuildResultTree(optimalKeyIndexes, startIndex, currentOptimalKeyIndex - 1, keys, tree->Left);
BuildResultTree(optimalKeyIndexes, currentOptimalKeyIndex + 1, endIndex, keys, tree->Right);
}
int main(int argc, char* argv[])
{
int keys[] = { 10, 12, 20 };
int freq[] = { 34, 8, 50 };
int n = sizeof(keys) / sizeof(keys[0]);
Matrix optimalKeyIndexes;
printf("Cost of Optimal BST is %d \n", optimalSearchTree(keys, freq, n, optimalKeyIndexes));
PrintResultTree(optimalKeyIndexes, 0, n - 1, keys);
TreeNode* tree = new TreeNode();
BuildResultTree(optimalKeyIndexes, 0, n - 1, keys, tree);
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.