【问题标题】:C: Recursive function - Binary searchC:递归函数 - 二分查找
【发布时间】:2015-01-19 11:59:45
【问题描述】:

我正在尝试构建一个递归函数,该函数通过与中间值进行比较并根据相对大小进行处理来返回排序数组中的地址。如果该值不在数组中,则应该简单地打印 NULL。现在该函数的第一部分可以工作,但是每当应该发生空值时,我都会遇到分段错误。代码如下:

#include <stdio.h> 

int *BinSearchRec(int arr[], int size, int n){
  if(n==arr[size/2]){
    return &arr[size/2];
  } 

  else if(n>arr[size/2]) {
    return(BinSearchRec(arr, size+size/2, n));
  }

  else if(n<arr[size/2]) {
    return(BinSearchRec(arr, size-size/2, n));
  }

  else{
    return NULL;                    
  }
 }

 main(){
    int numb[]={2,7,8,9};

 if((int)(BinSearchRec(numb, 4, 22)-numb)>=0)   {
    printf("Position: %d \n", (int)(BinSearchRec(numb, 4, 22)-numb)+1);
    }

     else{
       printf("NULL \n");
     }

  }

【问题讨论】:

  • 你的函数返回和int *,你把它当作int。还有NULL == 0 => NULL &gt;= 0
  • 这似乎是错误的,您将 size 添加到大于 sizesize/2 并且您最终会伸出您的阵列

标签: c segmentation-fault


【解决方案1】:

您的递归调用是错误的。在第一种情况下,您声称数组的大小比原来大 50%,并且您传递的指针错误(您应该传递数组的第二个“一半”)。

在这两种情况下,“数组”的大小始终是函数接收到的大小的一半。而在第二种情况下,您需要将指针传递给数组的后半部分。

类似

else if(n>arr[size/2]) {
  return(BinSearchRec(arr + sizeof/2, size/2, n));
}

else if(n<arr[size/2]) {
  return(BinSearchRec(arr, size/2, n));
}

您还错误地处理了函数的返回值。它不是一个值,它是一个指向该值的指针,你需要这样对待它。并且可以从另一个(相关)指针中减去一个指针,这称为指针算法

【讨论】:

  • 您的代码中有错字。应该是return(BinSearchRec(arr + size/2, size/2, n));
【解决方案2】:

除了其他人所说的未正确划分数组和未正确使用返回值之外,您的函数缺少终止条件。

在您的代码中,永远不会达到 las else,因为前面的三个条件涵盖了所有可能性:n 小于、等于或大于 arr[size/2]

在访问和比较它们之前,你应该测试你的子数组是否真的有元素。这是您的代码的修订版:

int *BinSearchRec(int arr[], int size, int n)
{
    int m = size/2;

    if (size == 0) return NULL;
    if (n > arr[m]) return BinSearchRec(arr + m + 1, size - m - 1, n);
    if (n < arr[m]) return BinSearchRec(arr, m, n);

    return &arr[m];
}

这是一个示例main,它显示了您如何使用返回的指针。如果指针为NULL,则该数字不在数组中,您不能取消对指针的引用。

int main()
{
    int numb[] = {2, 7, 8, 9};
    int n;

    for (n = 0; n < 15; n++) {
        int *p = BinSearchRec(numb, 4, n);

        if (p) {
            printf("%d: @%d\n", n, (int) (p - numb));
        } else {
            printf("%d: NULL\n", n);
        }
    }
    return 0;
}

【讨论】:

    【解决方案3】:

    与使用单个 size 相比,使用 2 个索引(leftright)分隔您正在探索的子数组更容易推理。 根据这种方法修改你的代码给出:

    #include <stdio.h> 
    #include <stdlib.h>
    
    int *BinSearchRec(int arr[], int left, int right, int n){
      if (left > right) 
        return NULL;
    
      int mid = (left + right) / 2;
    
      if(n == arr[mid])
        return &arr[mid];
    
      if(n > arr[mid])
        return BinSearchRec(arr, mid + 1, right, n);
      else
        return BinSearchRec(arr, left, mid - 1, n);
     }
    
    
    int main(int argc, char *argv[]){
      int numb[] = {2,7,8,9};
      int *p = BinSearchRec(numb, 0, 3, 22);
    
      if (p) {
        printf("Position: %d \n", (int) (p - numb + 1));
      } else {
        printf("NULL \n");
      }
      return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2020-11-13
      • 2015-12-02
      • 2011-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-16
      • 2021-04-08
      相关资源
      最近更新 更多