繁体   English   中英

数据结构中的二进制搜索和C中的算法分析

[英]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 *));

nmembsize这两个参数的类型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.

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