问题
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?
回答1:
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.
回答2:
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 );
来源:https://stackoverflow.com/questions/42971464/binary-search-in-data-structure-and-algorithm-analysis-in-c