【问题标题】:Optimal Binary Search Tree Wrong Output最优二叉搜索树错误输出
【发布时间】:2015-05-14 15:22:54
【问题描述】:

我正在解决一个问题,该问题通过尽可能最好的方式来计算二叉搜索树所需的最小遍历次数。我确实在网上遇到了一个解决方案,我已经理解了,但是我手动对样本输入进行了一些计算,并没有得到正确的结果。

下面是代码

#include <stdio.h>
#include <limits.h>

// A utility function to get sum of array elements freq[i] to freq[j]
int sum(int freq[], int i, int j);

/* A Dynamic Programming based function that calculates minimum cost of
   a Binary Search Tree. */
int optimalSearchTree(int keys[], int freq[], int n)
{
    /* Create an auxiliary 2D matrix to store results of subproblems */
    int cost[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[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+1; i++)
        {
            // Get column number j from row number i and chain length L
            int j = i+L-1;
            cost[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[i][r-1]:0) + 
                       ((r < j)? cost[r+1][j]:0) + 
                       sum(freq, i, j);
               if (c < cost[i][j])
                  cost[i][j] = c;
            }
        }
    }
    return cost[0][n-1];
}

// A utility function to get sum of array elements freq[i] to freq[j]
int sum(int freq[], int i, int j)
{
    int s = 0;
    for (int k = i; k <=j; k++)
       s += freq[k];
    return s;
}

// Driver program to test above functions
int main()
{
    int keys[] = {10, 12, 20};
    int freq[] = {34, 8, 50};
    int n = sizeof(keys)/sizeof(keys[0]);
    printf("Cost of Optimal BST is %d ", optimalSearchTree(keys, freq, n));
    return 0;
}

例如对于输入 整数键[] = {1,2,3}; 整数频率[] = {10,3,1};

我应该得到 18,但我得到 19

对于这个输入 整数键[] = {1,2,3,4}; 整数频率[] = {5,4,1,200};

我应该得到 225 我得到 226

对于这个输入 整数键[] = {1,2,3,4,5,6}; 整数频率[] = {33,1,409,2,1,34};

我应该得到 997,但我得到 556

对于这个输入 整数键[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; 整数频率[] = {5,5,5,5,5,5,5,5,5,5,167,5,5,5,5,5,5,5,5,5};

我应该得到 789,但我得到 532

怎么了?

【问题讨论】:

  • 您能否解释一下keysfreq 这些值代表什么以及您尝试应用的算法?
  • @chmike 这是一个很好的来源webcache.googleusercontent.com/…
  • 当您使用调试器并单步执行代码时,哪些行存在问题?
  • 案例:int keys[] = {1,2,3};整数频率 [] = {10,3,1};结果应该是 19
  • 假设您有三个词,A、B 和 C。您搜索 A 10 次、B 3 次和 C 1 次。您可以将它们排列为 A 在左分支上,B 和 C 在右分支上成对排列。就处理所有搜索必须遍历的边数而言,一条边需要 10 次遍历才能到达 A,然后要遍历 4 次边才能到达 B 和 C 对,然后向下 3 次边到 B,沿着边向下 1 到 C。这棵树的边遍历总数为 10 + 4 + 3 + 1,即 18。

标签: c algorithm dynamic-programming


【解决方案1】:

您对预期结果有误。以您的第一个示例为例,键为{1, 2, 3},频率为{10, 3, 1};最优二叉搜索树为:

1 (10) 个 \ 2 (3) \ 3 (1)

(括号中给出的频率)。该函数返回搜索树总和(频率)次的预期成本,以访问的节点数衡量,它是(10 * 1) + (3 * 2) + (1 * 3) = 19。每次搜索键 1 只遍历根节点。每次搜索key2都会遍历根节点,在其子节点中找到目标key,一共遍历了两个节点。类似地,每次搜索键 3 都要遍历三个节点。

根据访问的节点来衡量成本是有意义的,因为必须与每个访问节点的键进行比较,但您也可以根据遍历的边来衡量成本。但是,如果您计算进入根的边缘,则结果是相同的,它表示主机程序指向树的指针。在这种情况下,每个节点访问都涉及遍历该节点的传入边,消除节点访问或边遍历方面的计数成本之间的任何区别。

键为{1,2,3,4},频率为{5,4,1,200},最优二叉搜索树为

4 (200) / 1 (5) 个 \ 2 (4) \ 3 (1)

费用为(200 * 1) + (5 * 2) + (4 * 3) + (1 * 4) = 226

使用键{1,2,3,4,5,6} 和频率{33,1,409,2,1,34}

3 (409) / \ / \ 1 (33) 6 (34) \ / 2 (1) 4 (2) \ 5(1)

费用为(409 * 1) + ((33 + 34) * 2) + ((1 + 2) * 3) + (1 * 4) = 556

程序在每种情况下都返回正确的结果。

我将 20 键示例留给您作为练习。对于这种情况,有多个最优搜索树,但所有的成本都是 532,正如程序给出的那样。

【讨论】:

  • 假设您有三个词,A、B 和 C。您搜索 A 10 次、B 3 次和 C 1 次。您可以将它们排列为 A 在左分支上,B 和 C 在右分支上成对排列。就处理所有搜索必须遍历的边数而言,一条边需要 10 次遍历才能到达 A,然后要遍历 4 次边才能到达 B 和 C 对,然后向下 3 次边到 B,再往下边 1 到 C。这棵树的边遍历总数为 10 + 4 + 3 + 1,即 18。
  • @user2733436,程序计算节点访问,这是一个有效的成本度量。当且仅当您在计数中包含到根节点的传入边时,它等效于计算边遍历(这样做是有意义的,否则对存储在根节点中的键的搜索是免费的)。忽略树的根节点和右侧子节点中存储什么键的问题,搜索它所需的节点访问次数是 (10 * 2) + ((4 + 3) * 3) = 56,很多比我介绍的那棵树还要糟糕。
  • @user2733436,即使你计算边遍历,即使你不计算到达根的边遍历,你也算错了你的树。对于键 A 的每次搜索,您必须计算 1 次边遍历,对于 B 或 C 的每次搜索,您必须计算 1 次边遍历——一个从根到其右侧子节点,另一个从那里到目标节点。这使得 10 + (4 + 3) * 2 = 24,仍然比我的树差(如果你这样算的话,值为 18)。
  • @user2733436,无论如何,问题是为什么程序的输出与 OP 的期望不符,我已经通过准确描述程序正在做什么来回答这个问题。您可以随意反对它使用的成本衡量标准,但这与问题无关。
  • @user2733436,我明确统计了搜索树所涉及的节点访问次数,正如我所说,它肯定是19。计算在答案中给出。这也是搜索树所需的边遍历次数,假设您计算到根节点的传入边。如果您计算根的传入边,则搜索成本为(10 * 0) + (3 * 1) + (1 * 2) = 5
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-01
  • 1970-01-01
相关资源
最近更新 更多