C

时间:2016-11-15 00:07:12

标签: c search binary

第一次在这里发帖。我最近实施了二进制搜索,但有时我的输出将返回一个巨大的负数。现在我的第一个想法是我打印一个数字,我的指针指向一个随机的内存位置。有人可以帮助我修改逻辑以及如何改进我的代码吗?

#include <stdio.h>
#include <stdlib.h>

int binarysearch(int *array, int size, int target);

int main() {
    int array[] = { 1, 2, 3, 4, 5, 6 };
    printf("%d\n", binarysearch(array, 8, 15));
    return 0;
}

int binarysearch(int *array, int size, int target) {
    int mid;    
    mid = size / 2;

    if (size < 1) {
        return -1;
    }
    if (size == 1) {
        return array[0];
    }
    if (target == array[mid]) {
        return target;
    } else
    if (target < array[mid]) {
        binarysearch(array, mid, target);
    } else{
        binarysearch(array + mid, size - mid, target);
    }
}

3 个答案:

答案 0 :(得分:3)

对于初学者,你用数组中只有6个元素的元素数量无效来调用函数。

int array[] = { 1, 2, 3, 4, 5, 6 };
printf("%d\n", binarysearch(array, 8, 15));
                                  ^^^

此片段

if (size == 1) {
    return array[0];
}

不正确。第一个元素不必等于目标。

本声明

    binarysearch(array + mid, size - mid, target);

必须像

一样写
    binarysearch(array + mid + 1, size - mid - 1, target);

最后,该函数具有未定义的行为,因为它在这些情况下不返回任何内容

if (target < array[mid]) {
    binarysearch(array, mid, target);
} else{
    binarysearch(array + mid, size - mid, target);
}

你需要写

if (target < array[mid]) {
    return binarysearch(array, mid, target);
} else{
    return binarysearch(array + mid, size - mid, target);
}

关于编程风格的两个词。最好将功能命名为binary_search或类似binarySearch,或最后命名为BinarySearch,而不是binarysearch

一般来说,这不是一个好的功能设计。想象一下,数组有一个值为-1的元素。您如何确定该元素是否存在于数组中或不存在?

通常这样的函数会返回指向目标元素的指针(如果找到它),否则返回NULL指针。

这是一个演示程序,展示了如何实现这种方法。

#include <stdio.h>

int * binary_search( const int *a, size_t n, int target ) 
{
    if ( n == 0 ) return NULL;

    size_t middle = n / 2;

    if ( a[middle] < target )
    {
        return binary_search( a + middle + 1, n - middle - 1, target );
    }
    else if ( target < a[middle] )
    {
        return binary_search( a, middle, target );
    }

    return a + middle;
}

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

    for ( int i = 0; i < 8; i++ )
    {
        int *target = binary_search( array, N, i  );
        if ( target )
        {
            printf( "%d is found at position %d\n",  *target, ( int )(target - array ) );
        }
        else
        {
            printf( "%d is not found\n", i );
        }
    }

    return 0;
}

程序输出

0 is not found
1 is found at position 0
2 is found at position 1
3 is found at position 2
4 is found at position 3
5 is found at position 4
6 is found at position 5
7 is not found

顺便说一句,根据C标准函数main,没有参数应该声明为

int main( void )

答案 1 :(得分:2)

您拨打binarysearch(array, 8, 15)),但您的阵列只有6个条目。

以下是如何自动计算合适的尺寸:

int main(void) {
    int array[] = { 1, 2, 3, 4, 5, 6 };
    printf("%d\n", binarysearch(array, sizeof(array) / sizeof(array[0]), 15));
    return 0;
}

请注意,您的函数binarysearch也存在问题:

  1. 返回数组条目是假的,如果目标小于第一个条目,你会返回什么? -1不一定小于第一个条目。

  2. 您应该将索引返回到包含条目(如果找到)的数组中,如果找不到则-1

  3. 当你递归时,你不会从这些递归调用返回值:你应该在启用警告的情况下进行编译(例如:gcc -Wall -W)并查看编译器生成的所有有用的诊断消息。 / p>

  4. 以下是修改后的版本:

    int binarysearch(const int *array, int size, int target) {
    
        int a, b;
    
        for (a = 0, b = size; a < b;) {
            int mid = a + (b - a) / 2;
            if (target <= array[mid]) {
                b = mid;
            } else {
                a = mid + 1;
            }
        }
        // a is the offset where target is or should be inserted
        if (a < size && target == array[a])
            return a;
        else
            return -1;
    }
    

    注意:

    • 计算mid = (a + b) / 2;对于大尺寸可能不正确,因为可能存在算术溢出。自mid = a + (b - a) / 2;以来,a < b没有此问题。

    • 时间复杂度为 O(Log N),对于给定的size,该函数对所有目标值执行相同数量的步骤。

    • 如果数组包含多个与target相同的相同值,则binarysearch返回的索引是索引最低的匹配条目的索引。

答案 2 :(得分:1)

使用<stdlib.h>库提供的bsearch函数可以使这个问题更容易。

这样的事情:

#include <stdio.h>
#include <stdlib.h>

int cmpfunc(const void * a, const void * b);

int
main(void) {
    int array[] = {1, 2, 3, 4, 5, 6};
    size_t n = sizeof(array)/sizeof(*array);
    int *item;
    int key = 15;

    item = bsearch(&key, array, n, sizeof(*array), cmpfunc);

    if (item != NULL) {
        printf("Found item  = %d\n", *item);
    } else {
        printf("Item = %d could not be found\n", key);
    }

    return 0;
}

int 
cmpfunc(const void * a, const void * b) {
   return (*(int*)a > *(int*)b) - (*(int*)a < *(int*)b);
}

如果您不想使用bsearch,那么此方法也可以:

#include <stdio.h>
#include <stdlib.h>

#define BSFOUND 1
#define BS_NOT_FOUND 0

int cmpfunc(const void * a, const void * b);
int binary_search(int A[], int lo, int hi, int *key, int *locn);

int
main(void) {
    int array[] = {1, 2, 3, 4, 5, 6};
    size_t n = sizeof(array)/sizeof(*array);
    int key = 4, locn;

    if ((binary_search(array, 0, n, &key, &locn)) == BSFOUND) {
        printf("Found item = %d\n", array[locn]);
    } else {
        printf("Item = %d cound not be found\n", key);
    }

    return 0;
}

int
binary_search(int A[], int lo, int hi, int *key, int *locn) {
   int mid, outcome;

   if (lo >= hi) {
      return BS_NOT_FOUND;
   }

   mid = lo + (hi - lo) / 2;
   if ((outcome = cmpfunc(key, A+mid)) < 0) {
      return binary_search(A, lo, mid, key, locn);
   } else if(outcome > 0) {
      return binary_search(A, mid+1, hi, key, locn);
   } else {
      *locn = mid;
      return BSFOUND;
   }
}

int 
cmpfunc(const void * a, const void * b) {
   return (*(int*)a > *(int*)b) - (*(int*)a < *(int*)b);
}