简体   繁体   中英

binary search in Data Structure and Algorithm Analysis in C

When addressed the Binary_Search in chapter 2(2.4.4),the author mentioned that "

Notice that the variables cannot be declared unsigned(why?).In cases where the unsigned qualifier is questionable, we will not use it. As an example, if the unsigned qualifier is dependent on an array not beginning at zero, we will discard it. we will not use it. As an example, if the unsigned qualifier is dependent on an array not beginning at zero, we will discard it. We will also avoid using the unsigned type for variables that are counters in a for loop, because it is common to change the direction of a loop counter from increasing to decreasing and the unsigned qualifier is typically appropriate for the former case only. For example, the code in Exercise 2.10 does not work if i is declared unsigned. ".

The code as follow:

int binary_search( input_type a[ ], input_type x, unsigned int n )
{
int low, mid, high; /* Can't be unsigned; why? */
/*1*/ low = 0; high = n - 1;
/*2*/ while( low <= high )
{
/*3*/ mid = (low + high)/2;
/*4*/ if( a[mid] < x )
/*5*/ low = mid + 1;
else
/*6*/ if ( a[mid] < x )
/*7*/ high = mid - 1;
else
/*8*/ return( mid ); /* found */
}
/*9*/ return( NOT_FOUND );
}

Q: I can't understand that the variable cannot be declared unsigned.Why the unsigned qualifier is questionable? And how does unsigned qualifier change the direction of a loop counter from increasing to decreasing?

If mid is 0, you want the line high = mid - 1; to set high to -1, which will cause the loop to stop.

If the variables were unsigned, high would wrap around to the maximum unsigned value which would cause a read past the end of the buffer and a likely crash.

As for for loops which count down, the following loop will never end:

for (unsigned i = START_VAL; i >= 0; i--) {...}  //WRONG

Because i is unsigned, the condition i >= 0 will always be true.

The author of the book is wrong and it seems he is a weak programmer.:)

First of all it is a bad idea to use the type int as the size of an array. He should use the type size_t or at least the type ptrdiff_t defined in the header <stddef.h> because the value of size of an array can be greater than the value that the type int can accommodate.

Take into account that all C standard functions (as for example string functions) that deal with array sizes define corresponding parameters as having the type size_t .

Here is the declaration of the standard function bsearch .

void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));

The both parameters, nmemb and size , have type size_t .

The problem is not with signed or unsigned int type used as the type of the array size. The problem is how the algorithm is implemented.

For example he could implement the algorithm the following way as it is shown in the demonstrative program

#include <stdio.h>

size_t binary_search( const int a[], int x, size_t n )
{
    size_t low = 0, high = n;

    while ( low < high )
    {
        size_t middle = low + ( high - low ) / 2;

        if ( a[middle] < x )
        {
            low = middle + 1;
        }
        else if ( x < a[middle] )
        {
            high = middle;
        }
        else
        {
            return middle;
        }
    }

    return n;
}   

int main(void) 
{
    int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    size_t N = sizeof( a ) / sizeof( *a );

    for ( int i = -1; i <= a[N - 1] + 1; i++ )
    {
        printf( "x = %d: %zu\n", i, binary_search( a, i, N ) );
    }

    return 0;
}

The program output is

x = -1: 10
x = 0: 0
x = 1: 1
x = 2: 2
x = 3: 3
x = 4: 4
x = 5: 5
x = 6: 6
x = 7: 7
x = 8: 8
x = 9: 9
x = 10: 10

As you see if a value is not found in the array then the function returns the index that is equal to the size of the array.

Usually the binary search algorithm that returns the index of the target element is defined as the lower bound algorithm.

Here is an example of an implementation of the binary search algorithm that returns the lower position where the target element is present or could be inserted.

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

size_t binary_search( const int a[], int x, size_t n )
{
    size_t low = 0, high = n;

    while ( low < high )
    {
        size_t middle = low + ( high - low ) / 2;

        if ( a[middle] < x )
        {
            low = middle + 1;
        }
        else
        {
            high = middle;
        }
    }

    return high;
}   

int main(void) 
{
    const size_t N = 10;
    int a[N];

    srand( ( unsigned int )time( NULL ) );

    for ( size_t i = 0; i < N; i++ )
    {
        int value = rand() % ( int )N;

        size_t n = binary_search( a, value, i );

        if ( n != i )
        {
            memmove( a + n + 1, a + n, ( i - n ) * sizeof( int ) );
        }

        a[n] = value;

        for ( size_t j = 0; j < i + 1; j++ )
        {
            printf( "%d ", a[j] );
        }
        putchar( '\n' );
    }

    return 0;
}

The program output might look like

8 
1 8 
1 5 8 
0 1 5 8 
0 1 5 5 8 
0 0 1 5 5 8 
0 0 1 2 5 5 8 
0 0 1 2 2 5 5 8 
0 0 1 2 2 5 5 8 9 
0 0 1 2 2 5 5 5 8 9 

As you see neither signed int type is used in the implementation of the algorithm.

As for the loop shown in the other answer like this

for (unsigned i = START_VAL; i >= 0; i--) {...}  //WRONG

then again it is just written incorrectly. Instead of the for loop in this case there should be used do-while loop as for example

unsigned i = START_VAL;
do
{
    // ...
} while ( i-- != 0 );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM