简体   繁体   English

添加频率总和,求解最佳二叉树

[英]Adding sum of frequencies whille solving Optimal Binary search tree

I am referring to THIS problem and solution. 我指的是这个问题和解决方案。

Firstly, I did not get why sum of frequencies is added in the recursive equation. 首先,我不明白为什么将频率之和加到递归方程中。 在此处输入图片说明 Can someone please help understand that with an example may be. 有人可以帮忙理解一个例子。

In Author's word. 用作者的话来说。

We add sum of frequencies from i to j (see first term in the above formula), this is added because every search will go through root and one comparison will be done for every search. 我们将i到j的频率总和相加(请参见上式中的第一项),这是因为每次搜索都将经过根,并且每次搜索都将进行一次比较。

In code, sum of frequencies (purpose of which I do not understand) ... corresponds to fsum. 在代码中,频率之和(我不了解其目的)...对应于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;
}

Secondly, this solution will just return the optimal cost. 其次,该解决方案将仅返回最佳成本。 Any suggestions regarding how to get the actual bst ? 关于如何获得实际bst有什么建议吗?

Why we need sum of frequencies 为什么我们需要频率总和

The idea behind sum of frequencies is to correctly calculate cost of particular tree. 频率总和背后的想法是正确计算特定树的成本。 It behaves like accumulator value to store tree weight. 它的行为就像存储树重量的累加器值。

Imagine that on first level of recursion we start with all keys located on first level of the tree (we haven't picked any root element yet). 想象一下,在第一级递归中,我们从树的第一级上的所有键开始(我们尚未选择任何根元素)。 Remember the weight function - it sums over all node weights multiplied by node level. 记住权重函数-它求和所有节点权重乘以节点级别。 For now weight of our tree equals to sum of weights of all keys because any of our keys can be located on any level (starting from first) and anyway we will have at least one weight for each key in our result. 现在,我们树的权重等于所有键的权重之和,因为我们的任何键都可以位于任何级别(从第一层开始),并且无论如何,我们在结果中每个键的权重至少为一个。

1) Suppose that we found optimal root key, say key r . 1)假设我们找到了最佳根密钥,即密钥r Next we move all our keys except r one level down because each of the elements left can be located at most on second level (first level is already occupied). 接下来,我们将除r以外的所有键向下移动一个级别,因为剩下的每个元素最多可以位于第二个级别上(第一级别已被占用)。 Because of that we add weight of each key left to our sum because anyway for all of them we will have at least double weight. 因此,我们将剩下的每个键的权重加到总和上,因为无论如何,对于所有这些键,我们将至少具有两倍的权重。 Keys left we split in two sub arrays according to r element(to the left from r and to the right) which we selected before. 左边的键根据我们之前选择的r元素(从r到右边的左边)分成两个子数组。

2) Next step is to select optimal keys for second level, one from each of two sub arrays left from first step. 2)下一步是选择第二级的最佳键,从第一步剩下的两个子阵列中的每个子阵列中选择一个。 After doing that we again move all keys left one level down and add their weights to the sum because they will be located at least on third level so we will have at least triple weight for each of them. 之后,我们再次将所有按键向左下移一层,并将其权重添加到总和中,因为它们将至少位于第三层,因此每个按键的权重至少为三倍。

3) And so on. 3)依此类推。

I hope this explanation will give you some understanding of why we need this sum of frequencies. 我希望这种解释能使您对为什么我们需要这种频率总和有所了解。

Finding optimal bst 寻找最佳的BST

As author mentioned at the end of the article 正如作者在文章末尾提到的

2) In the above solutions, we have computed optimal cost only. 2)在上述解决方案中,我们仅计算了最佳成本。 The solutions can be easily modified to store the structure of BSTs also. 可以轻松修改解决方案以存储BST的结构。 We can create another auxiliary array of size n to store the structure of tree. 我们可以创建另一个大小为n的辅助数组来存储树的结构。 All we need to do is, store the chosen 'r' in the innermost loop. 我们要做的就是将所选的“ r”存储在最里面的循环中。

We can do just that. 我们可以做到这一点。 Below you will find my implementation. 在下面,您将找到我的实现。

Some notes about it: 一些注意事项:

1) I was forced to replace int[n][n] with utility class Matrix because I used Visual C++ and it does not support non-compile time constant expression as array size. 1)我被迫用实用程序类Matrix替换int[n][n] ,因为我使用了Visual C ++,并且它不支持非编译时间常数表达式作为数组大小。

2) I used second implementation of the algorithm from article which you provided (with memorization) because it is much easier to add functionality to store optimal bst to it. 2)我使用了您提供的文章的第二种算法实现(带有记忆),因为添加功能来存储最佳bst要容易得多。

3) Author has mistake in his code: Second loop for (int i=0; i<=n-L+1; i++) should have nL as upper bound not n-L+1 . 3)作者的代码有误: for (int i=0; i<=n-L+1; i++)第二个循环的上限应为nL而不是n-L+1

4) The way we store optimal bst is as follows: For each pair i, j we store optimal key index. 4)我们存储最佳bst的方式如下:对于每对i, j我们存储最佳密钥索引。 This is the same as for optimal cost but instead of storing optimal cost we store optimal key index. 这与最佳成本相同,但是我们存储最佳密钥索引而不是存储最佳成本。 For example for 0, n-1 we will have index of the root key r of our result tree. 例如,对于0, n-1我们将得到结果树的根键r的索引。 Next we split our array in two according to root element index r and get their optimal key indexes. 接下来,我们根据根元素索引r将数组分为两部分,并获得其最佳键索引。 We can dot that by accessing matrix elements 0, r-1 and r+1, n-1 . 我们可以通过访问矩阵元素0, r-1r+1, n-1 And so forth. 依此类推。 Utility function 'PrintResultTree' uses this approach and prints result tree in in-order (left subtree, node, right subtree). 实用程序功能“ PrintResultTree”使用此方法并按顺序(左子树,节点,右子树)打印结果树。 So you basically get ordered list because it is binary search tree. 因此,您基本上会获得有序列表,因为它是二进制搜索树。

5) Please don't flame me for my code - I'm not really a c++ programmer. 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);
}

Below is utility class Matrix : 以下是实用程序类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;
    }
};

And main method with utility function to print result tree in in-order: 和具有实用程序功能的主要方法按顺序打印结果树:

//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;
}

EDIT: 编辑:

Below you can find code to create simple tree like structure. 在下面,您可以找到创建简单树状结构的代码。

Here is utility TreeNode class 这是实用程序TreeNode

struct TreeNode
{
public:
    int Key;
    TreeNode* Left;
    TreeNode* Right;
};

Updated main function with BuildResultTree function 使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM