我不明白为什么我的递归函数没有按预期运行

I am not understanding why my recursive function is not behaving as I expect

我正在尝试创建一个函数,该函数 return 是数组中给定整数最右边位置的位置。示例:[1,2,3,4,5,6] 找到 4 的最右边位置将 return 4. [1,2,3,4,4,4,5,6] 找到最右边位置4 将 return 6.

我正在尝试在我的函数中实现递归调用。打印出递归调用时,我看到了正确的位置,尽管我最终遇到了麻烦 returning 该数字。

#include <stdio.h>

int RightMostBinarySearch(int *arr, int length, int find, int i, int j) {
    int middle = (i + j) / 2; //This will be floor due to integer data type
    while(i <= j){ //While the start does not excede int size of last value in array
        if(arr[middle] < find){ //If middle element is less than what is being searched for
            i = middle + 1; //Obviously the element is not found and the element is greater than middle point => make i one element to the right
        }
        else if(arr[middle] == find){ //The middle position is where the element exists in the array
            printf("%d\n", RightMostBinarySearch(arr, length, find, middle + 1, j));
            return middle + 1;
        }
        else{ //This condition will be when arr[midd] > find
            j = middle - 1; // make j 1 element left of middle because find is less than arr[middle]
        }
        middle = (i + j) / 2; //if not found i or j changes, thus middle must also change.
    }
    return -1;
}

int main(void) {
    int arr[] = { 1, 2, 4, 4, 4, 4, 4, 9, 12 }; //Sorted int array of size n
    int find = 4;
    int length = sizeof(arr) / sizeof(*arr); // Determines the length by getting the full size of memory array uses and dividing by he size of first element memory size. Full memory / element memory = num elements = length
    int i = 0;
    int j = length - 1; // Length of array is n, last element is represented n - 1
    int location = RightMostBinarySearch(arr,length, find, i, j);
    printf("The location of the element is at position: %d\n", location);
    return 0;
}

当函数 RightMostBinarySearch 递归时,您打印它的 return 值但总是 return middle + 1,这甚至可能不是 [=14= 的偏移量] 值出现。

你应该这样修改函数:

int RightMostBinarySearch(int *arr, int length, int find, int i, int j) {
    //While the start does not exceed int size of last value in array
    while (i <= j) {
        // This will be floor due to integer data type
        // Also avoid potential integer overflow in i+j
        // make sure the middle element is > i unless i == j
        int middle = i + (j - i + 1) / 2;
        //If middle element is less than what is being searched for
        if (arr[middle] < find) {
            //Obviously the element is not found and the element is greater than middle point => make i one element to the right
            i = middle + 1;
        } else
        if (arr[middle] == find) {
            //The middle position is where the element exists in the array
            if (middle == j) {
                /* middle is the last possible value */
                return middle;
            } else {
                return RightMostBinarySearch(arr, length, find, middle, j));
            }
        } else {
            //This condition will be when arr[midd] > find
            j = middle - 1; // make j 1 element left of middle because find is less than arr[middle]
        }
    }
    return -1;
}

请注意,这个问题不用递归函数也可以很容易地解决,用一个更简单的 API:

#include <stdio.h>

int LeftMostBinarySearch(const int *arr, int length, int find) {
    int i = 0;
    int j = length;

    while (i < j) {
        // compute mid-point avoiding potential overflow on i+j
        int middle = i + (j - i) / 2;
        if (arr[middle] < find) {
            i = middle + 1;
        } else {
            j = middle;
        }
    }
    if (i < length && arr[i] == find)
        return i;
    else
        return -1;
}

int RightMostBinarySearch(const int *arr, int length, int find) {
    int i = 0;
    int j = length;

    while (i < j) {
        // compute mid-point avoiding potential overflow on i+j
        int middle = i + (j - i) / 2;
        if (arr[middle] <= find) {
            i = middle + 1;
        } else {
            j = middle;
        }
    }
    if (i > 0 && arr[i - 1] == find)
        return i - 1;
    else
        return -1;
}

int main() {
    int arr[] = { 1, 2, 4, 4, 4, 4, 4, 9, 12 }; //Sorted int array
    int length = sizeof(arr) / sizeof(*arr); // Determines the length by getting the full size of memory array and dividing by the size of first element. Full memory / element memory = num elements = length
    int find = 4;
    int left_location = LeftMostBinarySearch(arr, length, find);
    int right_location = RightMostBinarySearch(arr, length, find);
    printf("The first element %d is at position: %d\n", find, left_location);
    printf("The last element %d is at position: %d\n", find, right_location);
    return 0;
}

如果您使用递归,我认为您不需要 while 循环?

我认为您可以通过以下方式找到此问题的解决方案。正如我所见,您应该 return 每一步。

int rmst(int *arr, int length, int find, int i, int j){                         
    if (i <= j) {                                                               
        int middle = (i+j)/2;                                                   
        if (arr[middle] < find){                                                
            return rmst(arr, length, find, middle+1, j);                        
        } else if (arr[middle] == find){                                        
            if ((middle + 1) < length){                                         
                if (arr[middle + 1] == find){ // continue binary search if the next guy is still == find, otherwise, return middle.                                   
                    return rmst(arr, length,find, middle+1, j);                
                }                                                               
            }                                                                   
            return middle;                                                      
        } else {                                                                
            return rmst(arr, length, find, i, middle -1);                       
        }                                                                       
    }                                                                           
                                                                                
    return -1;                                                                  
}

首先C中数组的索引从0开始。

其次,您的函数中未使用参数 length 的值。

第三,如果第一个 if 条件的计算结果为真,那么实际上您没有递归函数。您有一个带有 while 循环的迭代函数。

while(i <= j){ //While the start does not excede int size of last value in array
    if(arr[middle] < find){ //If middle element is less than what is being searched for
        i = middle + 1; //Obviously the element is not found and the element is greater than middle point => make i one element to the right
    }

    //...

    middle = (i + j) / 2; //if not found i or j changes, thus middle must also change.
}

因此,当变量 find 的值大于数组中的任何元素时,您就有了一个完全迭代的函数。

当这个if语句

    else if(arr[middle] == find){ //The middle position is where the element exists in the array
        printf("%d\n", RightMostBinarySearch(arr, length, find, middle + 1, j));
        return middle + 1;
    }

计算结果为真然后调用

RightMostBinarySearch(arr, length, find, middle + 1, j)

没有效果,函数 returns middle + 1 的值与 arr[middle + 1] 是否确实等于 find 无关。

函数参数过多。

最后,指定数组的参数应具有限定符 const,因为数组本身不会在函数内更改。

函数的声明和定义如下面的演示程序所示。

#include <stdio.h>

size_t RightMostBinarySearch( const int *a, size_t n, int value )
{
    if (n == 0)
    {
        return -1;
    }
    else if ( value < a[n / 2] )
    {
        return RightMostBinarySearch( a, n / 2, value );
    }
    else if ( a[n / 2] < value )
    {
        size_t result = RightMostBinarySearch( a + 1 + n / 2, n - 1 - n / 2, value );
        return result == -1 ? result : result + 1  + n / 2;
    }
    else
    {
        size_t result = RightMostBinarySearch( a + 1 + n / 2, n - 1 - n / 2, value );
        return result == -1 ? n / 2 : result + 1 + n / 2;
    }
}

int main( void )
{
    int a1[] = { 1, 2, 3, 4, 5, 6 };
    const size_t N1 = sizeof( a1 ) / sizeof( *a1 );

    printf( "%zu\n", RightMostBinarySearch( a1, N1, 4 ) );

    int a2[] = { 1, 2, 3, 4, 4, 4, 5, 6 };
    const size_t N2 = sizeof( a2 ) / sizeof( *a2 );

    printf( "%zu\n", RightMostBinarySearch( a2, N2, 4 ) );
}

程序输出为

3
5

如您所见,递归函数中既没有 while 语句也没有任何其他循环。