views:

469

answers:

2

I am solving "Programming Pearls" exercises. 4.11 say:

Write and prove the correctness of a recursive binary search function in C or C++ with this declaration:

int binarysearch(DataType x[], int n);

Use this function alone; do not call any other recursive function.

I came up with:

int bsearch_rec_array_only(int key, int* arr, int n)
{
    int mid;

    if (n < 0)
        return -1;

    mid = n / 2;

    if (arr[mid] == key)
        return (int) ((size_t) arr + mid * sizeof(*arr));
    else if (arr[mid] < key)
        return bsearch_rec_array_only(key, arr + mid + 1, n - mid - 1);
    else
        return bsearch_rec_array_only(key, arr, mid - 1);
}

However - there is problem. I return the offset including array address because otherwise how to know the relative offset of the element to original array?

So I need this wrapper:

int bsearch_array_only_wrap(int key, int* arr, int n)
{
    int offset;
    if (n == 0)
        return -1;

    offset = bsearch_rec_array_only(key, arr, n);

    if (offset == -1)
        return -1;
    else       
        return (offset - (int) arr) / sizeof(*arr);
}

It's not recursive - it just calls bsearch_rec_array_only and computes offset.

But this seems complicated. Can you find a better solution?

+1  A: 

Your problem is that the code doesn't return the offset of the element from the array's beginning, but a pointer cast into an int. The fact that you used a cast should show you that there something's wrong in the code.

Try returning an offset. Something like this:

if (arr[mid] == key)
        return mid;
else if (arr[mid] < key) {
        int i = bsearch_rec_array_only(key, arr + mid + 1, n - mid - 1);
        return (i != -1) ? i + mid + 1 : -1;
} else
        return bsearch_rec_array_only(key, arr, mid - 1);
Amnon
This works if you remember to check for -1 on the recursive calls.
Rickard
You're right, I hope it's correct now.
Amnon
but 'return mid' doesn't work, since the array a recursive call sees is not the real array, but some offset into it
zaharpopov
The point is that the function returns an index into the array it is given, not into any "real" array. When the function calls itself, the caller adjusts the index so it will be relative to the array the caller was given -- that's why we add (mid + 1) to the index in the 2nd case.
Amnon
it works, though it still needs a special fix for the case where originally it's passed n = 0. because this can happen during recursion in a valid way
zaharpopov
A: 

Here is the correct answer:

// Recursive binary search
int bsearch(int key, int * arr, int n)
{
    if (n == 0)
    {
        return -1;
    }

    int m = n / 2;
    int found;

    if (arr[m] == key)
    {
        found = m;
    }
    else if (arr[m] < key)
    {
        // Upper half. We'll search in upper half of the current array with new length 
        // of the upper half.
        found = bsearch(key, arr + m + 1, n - m - 1);

        if (found != -1)
        {
            // Since we've found a key, need to offset it to make valid in the 
            // current search scope
            found += m + 1;
        }
    }
    else
    {
        // Lower half, there is no need to offset the array. 
        // New array length is equal to the current middle point.
        found = bsearch(key, arr, m);
    }

    assert(found == -1 || (found >= 0 && found < n && arr[found] == key));

    return found;
}
Andrei Maksimenka