对整数数组之和进行划分和征服算法

时间:2014-10-13 15:58:30

标签: c++ arrays algorithm recursion divide-and-conquer

我在分治算法方面遇到了一些麻烦,并且正在寻求一些帮助。我正在尝试编写一个名为sumArray的函数来计算整数数组的总和。

此功能必须通过将数组分成两半并在每一半上执行递归调用来完成。我尝试使用类似的概念来编写递归求和算法时使用的概念,以及用于识别数组中最大元素的分而治之算法,但我很难将两种想法结合起来。

下面是我为sumArray编写的代码,它编译但不返回正确的结果。

int sumArray(int anArray[], int size)
{
    int total = 0;
    //base case
    if (size == 0)
    {
        return 0;
    }
    else if (size == 1)
    {
        return anArray[0];
    }

    //divide and conquer
    int mid = size / 2;
    int lsum = anArray [mid] + sumArray(anArray, --mid);
    int rsize = size - mid;
    int rsum = anArray[size - mid] + sumArray(anArray + mid, --rsize);
    return lsum + rsum;
}

我已经确定问题是该函数在计算rsum时包含lsum的值。我知道问题在于我使用rsize对sumArray的递归调用(一个等于原始数组大小的变量,减去中点)。但是,出于某种原因,我似乎无法确定修复方法。

我觉得很傻,因为我知道答案是正确地盯着我,但是我如何修复我的功能以便它返回准确的结果呢?

更新:感谢所有有用的回复,我修复了我的代码,以便编译并运行良好。我会留下我原来的代码,以防其他人在分裂和征服中挣扎,并可能犯同样的错误。有关正确解决问题的函数,请参阅@Laura M的答案。 @haris的回复也很好地解释了我的代码出现错误的位置。

5 个答案:

答案 0 :(得分:9)

int sumArray(int anArray[], int size)
{
    //base case
    if (size == 0)
    {
        return 0;
    }
    else if (size == 1)
    {
        return anArray[0];
    }

    //divide and conquer
    int mid = size / 2;
    int rsize = size - mid;
    int lsum = sumArray(anArray, mid);
    int rsum = sumArray(anArray + mid, rsize);
    return lsum + rsum;
}

答案 1 :(得分:4)

在您的代码中:

int mid = size / 2;
int lsum = anArray [mid] + sumArray(anArray, --mid);
int rsize = size - mid;
int rsum = anArray[size - mid] + sumArray(anArray + mid, --rsize);

我们可以通过数组为{ 2, 3, 4, 5, 6, 9}size = 6的示例来说明错误。

现在当你mid = size / 2,然后是:

int lsum = anArray [mid] + sumArray(anArray, --mid);
int rsize = size - mid;
int rsum = anArray[size - mid] + sumArray(anArray + mid, --rsize);

数字5会被添加两次(一次在lsum,然后在rsum),因为mid == (size - mid)

此外,sumArray()中对rsum的调用应该包含参数sumArray(anArray + (mid + 1), --rsize),因为mid已添加了元素lsum

另一方面,您可以使用更简单的递归代码,例如..

int add(int low,int high,int *a)
{
    int mid;
    if(high==low)
        return a[low];
    mid=(low+high)/2;
    return add(low,mid,a)+add(mid+1,high,a);
}

答案 2 :(得分:0)

int sumArray(int anArray[],int start,int end){
     if(start==end)
        return anArray[start];
     if(start<end){
         int mid=(start+end)/2;
         int lsum=sumArray(anArray,start,mid-1);
         int rsum=sumArray(anArray,mid+1,end);
         return lsum+rsum+anArray[mid];

     }
     return 0;

}

答案 3 :(得分:0)

正如哈里斯所说,在你的代码中你将相同的数字添加到正和和左和;但是,您的代码存在更大的问题。

您总是将相同的数组传递给lsum和rsum的递归调用。起初我认为这只是您实现的一部分,并且它将由size参数处理。但是,size参数似乎不起作用,因为您可能希望它起作用。 您的所有算法都会减小size参数,直到达到1.然后,触发基本情况,结果始终返回原始数组中的第一个项目。为什么?您永远不会在代码中拆分数组,因此在每次递归调用中都会保留相同的数组(即使在基本情况下也是如此)。

要解决这个问题,所有sumarray()应该做的是根据mid计算将数组拆分为左半部分和右半部分,并递归传递这个新数组,直到数组的大小为1(基本情况)然后返回数组中的项目。这有效地将数组分解为各自的元素,此时所有函数都要加上lsum和rsum。

伪代码:

sumArray(array[]){
    if size(array) is 1
          return array[0]

    mid = size(array) / 2 
    leftArray = splitArrayUpto(mid, array)
    rightArray = splitArrayAfter(mid+1, array)

    leftArraySum = sumArray(leftArray)
    rightArraySum = sumArray(rightArray)

    return leftArraySum + rightArraySum
 }   

答案 4 :(得分:0)

touch-action