C++ 需要帮助来解决我算法中的缺陷吗

C++ 需要帮助来解决我算法中的缺陷吗,c++,c,algorithm,C++,C,Algorithm,我正在为一家大型在线零售商的采访而练习,现在我正试图为两个排序数组的中值问题想出一个优雅的解决方案。我知道上面介绍的解决方案,但我正在尝试写一个替代方案。我已经写完了 include <stdio.h> int M2SA ( int * A, int m, int * B, int n ) { /* Returns the median of two sorted arrays A and B of lengths m and n respectively. A

我正在为一家大型在线零售商的采访而练习,现在我正试图为两个排序数组的中值问题想出一个优雅的解决方案。我知道上面介绍的解决方案,但我正在尝试写一个替代方案。我已经写完了

include <stdio.h>

int M2SA ( int * A, int m, int * B, int n )
{
   /* Returns the median of two sorted arrays A and B of lengths m and n respectively. 
      Assumes A and B aren't both empty. 
   */ 
   int ida = 0, idb = 0, idmed = (m+n)/2;
   while ((ida + idb) != idmed)
   {
     if (A[ida] < B[idb])
        ++ida;
     else
        ++idb;
   }
   return (A[ida] < A[idb] ? A[ida] : B[idb]);
} 



int main()
{
    int arr1 [] = {1, 1, 59, 69};
    int arr2 [] = {-4, 0, 49, 59, 59, 59};
    printf("%d", M2SA(arr1, sizeof(arr1)/sizeof(int), arr2, sizeof(arr2)/sizeof(int)));
    return 0;
}
打印出正确答案59,但我意识到我的算法有一个缺陷,只有当idmed不大于m或n时,我的算法才有效。例如,如果数组是{1}和{69,293,393,1923129},那么在while循环的第一次迭代之后,ida等于1,因此while循环的第二次迭代尝试访问[1]。然而,我想不出一个简单的方法来添加到我的代码中。有简单的吗?

也许你可以改变:

if (A[ida] < B[idb])
致:

以及:

致:

也许你可以改变:

if (A[ida] < B[idb])
致:

以及:

致:


基本上有3种情况需要考虑:

两个数组都没有被完全消耗。 第一个数组已消耗,中间值在第二个数组中。 第二个数组已消耗,中值在第一个数组中。 执行部门必须了解这3种情况。 三种情况中哪一种被触发取决于输入数据

例如,如果所有较小的值都在数组1中,而较大的值在数组2中,且数组1的长度小于数组2的长度,则数组1中的索引位于数组1的长度。所以访问它不是一个好主意

这里是一个使用for循环而不是while的实现。我更喜欢这里的for循环,因为更容易看到循环最终会终止

main函数包含一组测试用例,它们触发上述三条代码路径

int 
m2a
( _In_reads_(s1) const int * a1
, int s1
, _In_reads_(s2) const int *a2
, int s2
)
{
    int mi = (s1 + s2) / 2;
    int ai1 = 0;
    int ai2 = 0;
    for (int i = 0; i < mi;i++)
    {
        if (ai1 < s1 && ai2 < s2)
        {
            if (a1[ai1] < a2[ai2])
            {
                ai1++;
            }
            else
            {
                ai2++;
            }
        }
        else
        {
            if (ai1 < s1)
            {
                ai1++;
            }
            if (ai2 < s2)
            {
                ai2++;
            }
        }
    }
    int result = 0;
    if (ai1 < s1 && ai2 < s2)
    {
        result = a1[ai1] < a2[ai2] ? a1[ai1] : a2[ai2];
    }
    else
    {
        if (ai1 < s1)
        {
            result = a1[ai1];
        }
        if (ai2 < s2)
        {
            result = a2[ai2];
        }
    }
    return result;
}

int _tmain(int argc, _TCHAR* argv[])
{
    {
        const int s1 = 4;
        const int s2 = 4;
        int a1[s1] = { 1, 2, 3, 4 };
        int a2[s2] = { 1, 2, 3, 4 };
        int m = m2a(a1, s1, a2, s2);
        printf("%d\n", m);
    }
    {
        const int s1 = 5;
        const int s2 = 4;
        int a1[s1] = { 5,6,7,8,9 };
        int a2[s2] = { 1, 2, 3, 4 };
        int m = m2a(a1, s1, a2, s2);
        printf("%d\n", m);
    }
    {
        const int s1 = 4;
        const int s2 = 5;
        int a1[s1] = { 1, 2, 3, 4 }; 
        int a2[s2] = { 5, 6, 7, 8, 9 };
        int m = m2a(a1, s1, a2, s2);
        printf("%d\n", m);
    }
    {
        const int s1 = 1;
        const int s2 = 5;
        int a1[s1] = { 99 };
        int a2[s2] = { 5, 6, 7, 8, 9 };
        int m = m2a(a1, s1, a2, s2);
        printf("%d\n", m);
    }
    {
        const int s1 = 5;
        const int s2 = 1;
        int a1[s1] = { 5, 6, 7, 8, 9 };
        int a2[s2] = { 99 }; 
        int m = m2a(a1, s1, a2, s2);
        printf("%d\n", m);
    }

    {
        const int s1 = 5;
        const int s2 = 5;
        int a1[s1] = { 1,1,1,1,1 };
        int a2[s2] = { 1,1,1,1,1 };
        int m = m2a(a1, s1, a2, s2);
        printf("%d\n", m);
    }

    {
        const int s1 = 5;
        const int s2 = 1;
        int a1[s1] = { 5, 6, 7, 8, 9 };
        int a2[s2] = { 3 };
        int m = m2a(a1, s1, a2, s2);
        printf("%d\n", m);
    }
    return 0;
}

修复了剩余的错误。脑死亡胜过优雅。如果你有3个病例,试图隐藏是危险的。因此,循环体也显示了3种情况…

基本上有3种情况需要考虑:

两个数组都没有被完全消耗。 第一个数组已消耗,中间值在第二个数组中。 第二个数组已消耗,中值在第一个数组中。 执行部门必须了解这3种情况。 三种情况中哪一种被触发取决于输入数据

例如,如果所有较小的值都在数组1中,而较大的值在数组2中,且数组1的长度小于数组2的长度,则数组1中的索引位于数组1的长度。所以访问它不是一个好主意

这里是一个使用for循环而不是while的实现。我更喜欢这里的for循环,因为更容易看到循环最终会终止

main函数包含一组测试用例,它们触发上述三条代码路径

int 
m2a
( _In_reads_(s1) const int * a1
, int s1
, _In_reads_(s2) const int *a2
, int s2
)
{
    int mi = (s1 + s2) / 2;
    int ai1 = 0;
    int ai2 = 0;
    for (int i = 0; i < mi;i++)
    {
        if (ai1 < s1 && ai2 < s2)
        {
            if (a1[ai1] < a2[ai2])
            {
                ai1++;
            }
            else
            {
                ai2++;
            }
        }
        else
        {
            if (ai1 < s1)
            {
                ai1++;
            }
            if (ai2 < s2)
            {
                ai2++;
            }
        }
    }
    int result = 0;
    if (ai1 < s1 && ai2 < s2)
    {
        result = a1[ai1] < a2[ai2] ? a1[ai1] : a2[ai2];
    }
    else
    {
        if (ai1 < s1)
        {
            result = a1[ai1];
        }
        if (ai2 < s2)
        {
            result = a2[ai2];
        }
    }
    return result;
}

int _tmain(int argc, _TCHAR* argv[])
{
    {
        const int s1 = 4;
        const int s2 = 4;
        int a1[s1] = { 1, 2, 3, 4 };
        int a2[s2] = { 1, 2, 3, 4 };
        int m = m2a(a1, s1, a2, s2);
        printf("%d\n", m);
    }
    {
        const int s1 = 5;
        const int s2 = 4;
        int a1[s1] = { 5,6,7,8,9 };
        int a2[s2] = { 1, 2, 3, 4 };
        int m = m2a(a1, s1, a2, s2);
        printf("%d\n", m);
    }
    {
        const int s1 = 4;
        const int s2 = 5;
        int a1[s1] = { 1, 2, 3, 4 }; 
        int a2[s2] = { 5, 6, 7, 8, 9 };
        int m = m2a(a1, s1, a2, s2);
        printf("%d\n", m);
    }
    {
        const int s1 = 1;
        const int s2 = 5;
        int a1[s1] = { 99 };
        int a2[s2] = { 5, 6, 7, 8, 9 };
        int m = m2a(a1, s1, a2, s2);
        printf("%d\n", m);
    }
    {
        const int s1 = 5;
        const int s2 = 1;
        int a1[s1] = { 5, 6, 7, 8, 9 };
        int a2[s2] = { 99 }; 
        int m = m2a(a1, s1, a2, s2);
        printf("%d\n", m);
    }

    {
        const int s1 = 5;
        const int s2 = 5;
        int a1[s1] = { 1,1,1,1,1 };
        int a2[s2] = { 1,1,1,1,1 };
        int m = m2a(a1, s1, a2, s2);
        printf("%d\n", m);
    }

    {
        const int s1 = 5;
        const int s2 = 1;
        int a1[s1] = { 5, 6, 7, 8, 9 };
        int a2[s2] = { 3 };
        int m = m2a(a1, s1, a2, s2);
        printf("%d\n", m);
    }
    return 0;
}

修复了剩余的错误。脑死亡胜过优雅。如果你有3个病例,试图隐藏是危险的。因此,循环的主体还显示了3种情况…

以下是对您的解决方案的优雅修复:

int ida = 0, idb = 0, idmed = (m + n) / 2;
while (ida < m && idb < n && ida + idb < idmed) {
    A[ida] < B[idb] ? ++ida : ++idb;
}
if (ida == m) return B[idmed - m];
if (idb == n) return A[idmed - n];
return A[ida] < B[idb] ? A[ida] : B[idb];

以下是对您的解决方案的优雅修复:

int ida = 0, idb = 0, idmed = (m + n) / 2;
while (ida < m && idb < n && ida + idb < idmed) {
    A[ida] < B[idb] ? ++ida : ++idb;
}
if (ida == m) return B[idmed - m];
if (idb == n) return A[idmed - n];
return A[ida] < B[idb] ? A[ida] : B[idb];

偶数长度序列中位数的一个广泛使用的定义是,取中位数周围两个相邻数字的算术平均值作为结果。中位数[1;2;3;4]=2+3/2=2.5你基本上采取了解决问题的方法,这一方法是有效的。因此,您必须像处理合并排序一样处理列表结束条件。偶数长度序列中位数的一个广泛使用的定义是将中位数周围的两个相邻数字的算术平均值作为结果。中位数[1;2;3;4]=2+3/2=2.5你基本上采取了解决问题的方法,这一方法是有效的。因此,您必须像处理合并排序一样处理列表结束条件?这并不常见。开头的逗号真的让我讨厌,但这在某种程度上是风格上的,所以每个逗号都有自己的特点。它帮助静态代码检查器查找数组错误,并且通常以工具可以访问的方式注释参数和函数。我更喜欢前导逗号而不是尾随逗号,因为我可以简单地在一行中放置一条注释,然后就可以完成了。在最后一个测试用例中,将99替换为3,您会发现您有一个数组错误。_In_readss1符号从何而来?这并不常见。开头的逗号真的让我讨厌,但这在某种程度上是风格上的,所以每个逗号都有自己的特点。它帮助静态代码检查器查找数组错误,并且通常以工具可以访问的方式注释参数和函数。我更喜欢前导逗号而不是尾随逗号,因为我可以简单地在一行中放置一条注释,然后就可以完成了。在最后一个测试用例中,用3替换99,你会发现你有一个数组错误。