C中的二进制搜索 - 卡在循环中

时间:2018-02-12 02:46:58

标签: c sorting infinite-loop

我正在尝试编写一个程序,它接受一个数字数组并使用二进制搜索方法将它们分类到一个新数组中。现在,我陷入无限循环,因为:if( &arr[mid_val] != NULL)保持返回true,即使我已将int *arr初始化为NULL

为什么会这样?它应该在第一次迭代时不返回false吗?

代码:

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

int binary_search( int *arr, int to_find, int size ) {
    int mid_val;
    int new_size;
    int return_val;
    int *new_arr;

    mid_val = size / 2;

    printf("infinite\n");

    if( &arr[mid_val] != NULL ) {    /* why does this return true in the first iteration? */
        if( to_find > arr[mid_val] ) {
            /* second half of arr */
            new_arr = malloc( sizeof( int ) * ( mid_val ) );
            memcpy( new_arr, &arr[mid_val], sizeof( int ) * ( mid_val ) );
            new_size = mid_val;

            return_val = mid_val + binary_search( new_arr, to_find, new_size );

            return return_val;
        }
        else if( to_find < arr[mid_val] ) {
            /* first half of arr */
            new_arr = malloc( sizeof( int ) * ( mid_val ) );
            memcpy( new_arr, arr, sizeof( int ) * ( mid_val ) );
            new_size = mid_val;

            return_val = binary_search( new_arr, to_find, new_size );

            return return_val;
        }
    }
    return 0;
}

int main ( ) {
    int i;
    int pos;
    int size = 0;
    int numbers[10] = { 5, 8, 12, 2, 1, 0, 9, 22, 21, 55 };
    int *arr = NULL;

    for( i = 0; i < 10; i++) {
        arr = realloc( arr, sizeof( int ) * ( size + 1 ) );

        pos = binary_search( arr, numbers[i], size );

        memcpy( &arr[pos + 1], &arr[pos], ( size - pos ) * sizeof( int ) );
        memcpy( &arr[pos], &numbers[i], sizeof( int ) );

        size++;
    }

    for(i = 0; i < size; i++){
        printf("%d\n", arr[i]);
    }

    return 0;
}

2 个答案:

答案 0 :(得分:1)

你的记忆就像破水管一样。

if( &arr[mid_val] != NULL ) {    /* why does this return true in the first iteration? */

除非mid_val为0且arrNULL,否则始终为真。 表达式arr[mid_val]等同于arr + mid_val,其中 mid_val不为0会返回arr指向的地址 偏移mid_val * sizeof(*arr)

您需要做的是先检查arr是否NULL。如果是NULL 然后返回错误值。

int binary_search( int *arr, int to_find, int size ) {
    ...

    if(arr == NULL)
        return -1;  // negative index == error
}

在这个块中:

new_arr = malloc( sizeof( int ) * ( mid_val ) );
memcpy( new_arr, &arr[mid_val], sizeof( int ) * ( mid_val ) );
new_size = mid_val;

return_val = mid_val + binary_search( new_arr, to_find, new_size );

return return_val;

您正在为半角数组的副本分配内存。但你永远不会 释放你的代码泄漏的记忆。你应该这样做:

return_val = mid_val + binary_search( new_arr, to_find, new_size );

free(new_arr);
return return_val;

如果您的搜索没有找到任何内容,则应返回-1。 0是有效索引, 如何区分错误和有效索引?

此外,您还没有真正的终端案例进行迭代,最终mid_val 将达到0并且您将继续调用大小为0的malloc。递归将 仅在malloc返回NULL或您已达到递归限制时结束。 在这两种情况下,你都消耗了这么多资源 系统会终止您的程序,或者以段错误结束。

请注意,malloc(0)不一定会返回NULL

  

man malloc

#include <stdlib.h>

void *malloc(size_t size);
     

返回值

     

malloc()calloc()函数返回指向已分配内存的指针,该内存适合任何内置类型。   出错时,这些函数返回NULL。成功调用大小为零的NULL或成功调用也会返回malloc()   致电calloc() nmembsize等于零。

它说可能,而不是 。其他消息来源说:

  

http://pubs.opengroup.org/onlinepubs/009695399/functions/malloc.html

     

返回的指针指向分配空间的开始(最低字节地址)。如果无法分配空间,则应返回空指针。 如果请求的空间大小为0,则行为是实现定义的:返回的值应为空指针或唯一指针。

在任何情况下,您都无法转发malloc返回NULL的终端案例 当你请求0个字节时。

但是代码中所有问题的最大问题是binary search算法的设计可以解决 排序数组。如果数组未排序,则仅在空间中搜索 中间元素之前/之后没有意义,因为不能保证 中元素后面的所有元素都比较大,所有元素都在前面 中元素分别较小。您的初始数组未排序,二进制 搜索毫无意义。

我认为使用malloc进行二分查找非常浪费资源, 您只需要传递搜索空间的开头和结尾即可。这是一个 可能实现二进制搜索,注意数组是否排序 首先。互联网上有很多这样的示例实现,a 简单的谷歌搜索在第一页显示一些版本。

#include <stdio.h>
#include <string.h>

int binary_search(int *arr, int to_find, size_t start, size_t end)
{
    if(arr == NULL)
        return -1;

    if(start == end)
    {
        if(arr[start] == to_find)
            return start;

        return -1; // not found
    }


    int index;
    int mid = start + (end - start) / 2;

    if(arr[mid] == to_find)
        return mid;

    if(to_find < arr[mid])
        index = binary_search(arr, to_find, start, mid - 1);
    else
        index = binary_search(arr, to_find, mid + 1, end);

    return index;
}


int main(void)
{
    int numbers[] = { -19, -17, -3, 0, 5, 9, 12, 13, 14, 18, 20, 44, 77, 122, 888 };

    size_t arrlen = sizeof numbers / sizeof *numbers;

    int index;
    int search[] = { -19, -17, -3, 0, 5, 9, 12, 13, 14, 18, 20, 44, 77, 122, 888, 32, 50 };

    for(size_t i = 0; i < sizeof search / sizeof *search; ++i)
    {
        index = binary_search(numbers, search[i], 0, arrlen - 1);

        if(index == -1)
            printf("Number %d not found\n", search[i]);
        else
            printf("Number %d found at index: %d\n", search[i], index);
    }

    return 0;
}

输出

Number -19 found at index: 0
Number -17 found at index: 1
Number -3 found at index: 2
Number 0 found at index: 3
Number 5 found at index: 4
Number 9 found at index: 5
Number 12 found at index: 6
Number 13 found at index: 7
Number 14 found at index: 8
Number 18 found at index: 9
Number 20 found at index: 10
Number 44 found at index: 11
Number 77 found at index: 12
Number 122 found at index: 13
Number 888 found at index: 14
Number 32 not found
Number 50 not found

答案 1 :(得分:0)

  

if(arr [mid_val]!= NULL)保持返回true,即使我已将int * arr初始化为NULL

如果arr为NULL,则为dereferencing a null pointer。您需要为arr分配内存以指向并初始化该内存的内容。

请注意,int *arr表示您要搜索的数组。如果为null,则无需搜索。

你可能想说你为arr分配了内存并用一些东西填充内存......零?用NULL填充它没有意义。正如@lurker在评论中指出的那样,将整数与NULL进行比较可能不是你想要的。