[英]binary search in Data Structure and Algorithm Analysis in C
在第2(2.4.4)章中提到Binary_Search时,作者提到 “
注意变量不能声明为unsigned(why?),如果unsigned限定词有问题,我们将不使用它。 例如,如果无符号限定符依赖于不是从零开始的数组,我们将丢弃它。 我们不会使用它。 例如,如果无符号限定符依赖于不是从零开始的数组,我们将丢弃它。 我们还将避免对for循环中作为计数器的变量使用无符号类型,因为通常将循环计数器的方向从增加更改为递减,并且无符号限定符通常仅适用于前一种情况。 例如,如果我被声明为无符号,则练习2.10中的代码将无法工作。 ”。
代码如下:
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 );
}
问:我不明白不能将变量声明为unsigned。为什么unsigned限定词有问题? 无符号限定符如何将循环计数器的方向从增加变为减少?
如果mid
为0,则您希望线high = mid - 1;
将high
设置为-1,这将导致环路停止。
如果变量是无符号的,则high
将回绕到最大无符号值,这将导致读取超出缓冲区末尾并可能导致崩溃。
对于递减计数的循环,以下循环将永远不会结束:
for (unsigned i = START_VAL; i >= 0; i--) {...} //WRONG
因为i
是无符号的,所以条件i >= 0
将始终为真。
这本书的作者是错误的,似乎他是一个虚弱的程序员。
首先,将int
类型用作数组的大小是一个坏主意。 他应该使用size_t
类型或至少在标头<stddef.h>
定义的ptrdiff_t
类型,因为数组的size值可以大于int
类型可以容纳的值。
考虑到所有处理数组大小的C标准函数(例如字符串函数)都将相应的参数定义为size_t
类型。
这是标准函数bsearch
的声明。
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
nmemb
和size
这两个参数的类型nmemb
size_t
。
问题不在于将有符号或无符号int类型用作数组大小的类型。 问题是如何实现算法。
例如,他可以按照演示程序中所示的以下方式实现该算法
#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;
}
程序输出为
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
如您所见,如果在数组中未找到值,则该函数返回的索引等于数组的大小。
通常,将返回目标元素索引的二进制搜索算法定义为下限算法。
这是二进制搜索算法的实现示例,该算法返回存在或可以插入目标元素的较低位置。
#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;
}
程序输出可能看起来像
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
如您所见,在算法的实现中都没有使用带符号的int
类型。
至于其他答案所示的循环
for (unsigned i = START_VAL; i >= 0; i--) {...} //WRONG
然后再次将其写错。 在这种情况下,应使用do-while
循环代替for
循环,例如
unsigned i = START_VAL;
do
{
// ...
} while ( i-- != 0 );
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.