Jump to: navigation, search

The C Programming Language, 2nd Edition, by Kernighan and Ritchie
Exercise 3.01 on page 58

Our binary search makes two tests inside the loop, when one would suffice (at the price of more tests outside). Write a version with only one test inside the loop and measure the difference in run-time.



Solution by Paul Griffiths

/* Solution by Paul Griffiths (mail@paulgriffiths.net) */

/*
  
  EX3_1.C
  =======

  Suggested solution to Exercise 3-1

*/

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

int binsearch(int x, int v[], int n);     /*  Original K&R function  */
int binsearch2(int x, int v[], int n);    /*  Our new function       */

#define MAX_ELEMENT 20000


/*  Outputs approximation of processor time required
    for our two binary search functions. We search for
    the element -1, to time the functions' worst case
    performance (i.e. element not found in test data)   */

int main(void) {
    int testdata[MAX_ELEMENT];
    int index;                  /*  Index of found element in test data  */
    int n = -1;                 /*  Element to search for  */
    int i;
    clock_t time_taken;

    /*  Initialize test data  */
    
    for ( i = 0; i < MAX_ELEMENT; ++i )
        testdata[i] = i;
    
    
    /*  Output approximation of time taken for
        100,000 iterations of binsearch()       */
    
    for ( i = 0, time_taken = clock(); i < 100000; ++i ) {
        index = binsearch(n, testdata, MAX_ELEMENT);
    }
    time_taken = clock() - time_taken;
    
    if ( index < 0 )
        printf("Element %d not found.\n", n);
    else
        printf("Element %d found at index %d.\n", n, index);
    
    printf("binsearch() took %lu clocks (%lu seconds)\n",
           (unsigned long) time_taken,
           (unsigned long) time_taken / CLOCKS_PER_SEC);
    
    
    /*  Output approximation of time taken for
        100,000 iterations of binsearch2()        */
    
    for ( i = 0, time_taken = clock(); i < 100000; ++i ) {
        index = binsearch2(n, testdata, MAX_ELEMENT);
    }
    time_taken = clock() - time_taken;
    
    if ( index < 0 )
        printf("Element %d not found.\n", n);
    else
        printf("Element %d found at index %d.\n", n, index);
    
    printf("binsearch2() took %lu clocks (%lu seconds)\n",
           (unsigned long) time_taken,
           (unsigned long) time_taken / CLOCKS_PER_SEC);
    
    return 0;
}


/*  Performs a binary search for element x
        in array v[], which has n elements      */

int binsearch(int x, int v[], int n) {
    int low, mid, high;
    
    low = 0;
    high = n - 1;
    while ( low <= high ) {
        mid = (low+high) / 2;
        if ( x < v[mid] )
            high = mid - 1;
        else if ( x > v[mid] )
            low = mid + 1;
        else
            return mid;
    }
    return -1;
}


/*  Implementation of binsearch() using
    only one test inside the loop        */

int binsearch2(int x, int v[], int n) {
    int low, high, mid;
    
    low = 0;
    high = n - 1;
    mid = (low+high) / 2;
    while ( low <= high && x != v[mid] ) {
        if ( x < v[mid] )
            high = mid - 1;
        else
            low = mid + 1;
        mid = (low+high) / 2;
    }
    if ( x == v[mid] )
        return mid;
    else
        return -1;
}

Solution by Colin Barker

/* Solution by Colin Barker (colin.barker@wanadoo.fr)
 * using the driver from the solution by Paul Griffiths.
 */

/*
  
  EX3_1.C
  =======

  Suggested solution to Exercise 3-1

*/

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

int binsearch(int x, int v[], int n);     /*  Original K&R function  */
int binsearch2(int x, int v[], int n);    /*  Our new function       */

#define MAX_ELEMENT 20000


/*  Outputs approximation of processor time required
    for our two binary search functions. We search for
    the element -1, to time the functions' worst case
    performance (i.e. element not found in test data)   */

int main(void) {
    int testdata[MAX_ELEMENT];
    int index;                  /*  Index of found element in test data  */
    int n = -1;                 /*  Element to search for  */
    int i;
    clock_t time_taken;

    /*  Initialize test data  */
    
    for ( i = 0; i < MAX_ELEMENT; ++i )
        testdata[i] = i;
    
    
    /*  Output approximation of time taken for
        100,000 iterations of binsearch()       */
    
    for ( i = 0, time_taken = clock(); i < 100000; ++i ) {
        index = binsearch(n, testdata, MAX_ELEMENT);
    }
    time_taken = clock() - time_taken;
    
    if ( index < 0 )
        printf("Element %d not found.\n", n);
    else
        printf("Element %d found at index %d.\n", n, index);
    
    printf("binsearch() took %lu clocks (%lu seconds)\n",
           (unsigned long) time_taken,
           (unsigned long) time_taken / CLOCKS_PER_SEC);
    
    
    /*  Output approximation of time taken for
        100,000 iterations of binsearch2()        */
    
    for ( i = 0, time_taken = clock(); i < 100000; ++i ) {
        index = binsearch2(n, testdata, MAX_ELEMENT);
    }
    time_taken = clock() - time_taken;
    
    if ( index < 0 )
        printf("Element %d not found.\n", n);
    else
        printf("Element %d found at index %d.\n", n, index);
    
    printf("binsearch2() took %lu clocks (%lu seconds)\n",
           (unsigned long) time_taken,
           (unsigned long) time_taken / CLOCKS_PER_SEC);
    
    return 0;
}


/*  Performs a binary search for element x
        in array v[], which has n elements      */

int binsearch(int x, int v[], int n) {
    int low, mid, high;
    
    low = 0;
    high = n - 1;
    while ( low <= high ) {
        mid = (low+high) / 2;
        if ( x < v[mid] )
            high = mid - 1;
        else if ( x > v[mid] )
            low = mid + 1;
        else
            return mid;
    }
    return -1;
}

int binsearch2(int x, int v[], int n)
{
  int low, high, mid;

  low = -1;
  high = n;
  while (low + 1 < high) {
    mid = (low + high) / 2;
    if (v[mid] < x)
      low = mid;
    else
      high = mid;
  }
  if (high == n || v[high] != x)
    return -1;
  else
    return high;
}

Solution by Andrew Tesker

/* Andrew Tesker
 *
 * krx30102.c
 */

#include <stdio.h>

/* find x in v[] */
int binsearch(int x, int v[], int n);

/*
  The main is here for the purpose of a built in test
  
 */


int main(void)
{
  int test[]={1,3,5,7,9,11,13};
  int i;
  for(i=(sizeof(test)/sizeof(int))-1; i>=0; --i)
    printf("looking for %d. Index=%d\n",test[i],binsearch(test[i], test, sizeof(test)/sizeof(*test)));

  return 0;

}
/* n = size of array v */

int binsearch(int x, int v[], int n)
{
  int low, high, mid;

  low = 0;
  high = n-1;
  
  while(low < high) {
    mid = (low+high)/2;
    if(x <= v[mid]) 
      high=mid;
    
    else 
      low = mid+1;
  }
  
  return (x == v[low])?low : -1;

}


Solution by Alejandro A. Buezo

/* Alejandro A. Buezo (aabuezo@yahoo.com.ar) 
 * Date: 2017-17-09
 */

/*
 * EX3_1.C
 * =======
 * Just another suggested solution to Exercise 3-1
 */

#include <stdio.h>

int binsearch(int, int [], int);                                            /*  binary search by Kernighan and Ritchie  */
int binsearch2(int, int [], int);                                                                /*  Another binsearch  */

#define MAX_ELEMENT 20000



int main(void) {
    int data_array[MAX_ELEMENT];                                /*  Ordered array of ints where to search for elements  */
    int values_to_check[] = {-1, 0, 1, 2, MAX_ELEMENT-1, MAX_ELEMENT, MAX_ELEMENT +1};      /*  Elements to search for  */
    int size = sizeof(values_to_check) / sizeof(int);                                      /*  sizeof(values_to_check)  */
    int indexes[size];                                                     /*  Indexes of found elements in data_array  */
    int i;

    /*  Initialize data  */
    for ( i = 0; i < MAX_ELEMENT; i++ )
        data_array[i] = i;
    

    /*  Testing binsearch  */
    for ( i = 0; i < size; i++ ) 
        indexes[i] = binsearch(values_to_check[i], data_array, MAX_ELEMENT);
    
    /*  Print binsearch results  */
    printf("binsearch:\n");    
    for( i = 0; i < size; i++) 
        if ( indexes[i] < 0 )
            printf("Element %d not found.\n", values_to_check[i]);
        else
            printf("Element %d found at index %d.\n", values_to_check[i], indexes[i]);


    /*  Testing binsearch2  */
    for ( i = 0; i < size; i++ ) 
        indexes[i] = binsearch2(values_to_check[i], data_array, MAX_ELEMENT);
    
    /*  Print binsearch2 results  */
    printf("binsearch2:\n");
    for( i = 0; i < size; i++) 
        if ( indexes[i] < 0 )
            printf("Element %d not found.\n", values_to_check[i]);
        else
            printf("Element %d found at index %d.\n", values_to_check[i], indexes[i]);

    return 0;
}


/*  binsearch: busca x en v[0] <= v[1] ... <= v[n]  */
int binsearch(int x, int v[], int n)
{
    int mid;
    int low = 0;
    int high = n-1;

    while(low <= high) {
        mid = (low + high) / 2;
        if(x < v[mid])
            high = mid - 1;
        else if(x > v[mid])
            low = mid + 1;
        else
            return mid;     
    }
    return -1;              
}


/*  binsearch2  */
int binsearch2(int x, int v[], int n)
{
    int low, mid, high;
    
    low = 0;
    high = n-1;
    
    while( low <= high && x != v[mid = (low + high) / 2] ) {
        if( x < v[mid] )
            high = mid - 1;
        else 
            low = mid + 1;
    }
    return ( x == v[mid] ? mid : -1);
}

/*  can be shorter 
int binsearch2(int x, int v[], int n)
{
    int low, mid, high;
    
    low = 0;
    high = n-1;
    
    while( low <= high && x != v[mid = (low + high) / 2] ) 
        ( x < v[mid] ) ? high = mid - 1 : low = mid + 1;
    
    return ( x == v[mid] ? mid : -1 );
}  */


/*  using n as high, but not so legible
int binsearch2(int x, int v[], int n)
{
    int low = 0, mid;
    n--;
    
    while( low <= n && x != v[mid = (low + n) / 2] ) 
        ( x < v[mid] ) ? n = mid - 1 : low = mid + 1;
    
    return ( x == v[mid] ? mid : -1 );
}  */

Solution by Luke Panayi

All these solutions putting condition checks at the top of the while loops are cheating!

#include <stdio.h>

int binsearch(int x, int v[], int n)	{

	int low, mid, high;
	
	low = 0;
	high = n-1;
	while (low < high)	{
		mid = (low+high)/2;
		if (x <= v[mid])
			high = mid;
		else
			low = mid + 1;
	}

	if (x == v[low])
		return low;
	else
		return -1;
}

/*
both functions are timed to 0.001 seconds (I guess it's easier to see the difference on CPU's from the 80's)
however, in reality the new binsearch has a better worst case but a worse best cas
as the old one would instantly return if input was best case, while the new one still has
to iterate a few times, even if they're faster iterations.
*/

int main()	{ 
	int var[] = {0,1,2,3,4,5,6,7,8,9};
	printf("%d\n", binsearch(4,var,10));
	return 0;
}


Solution by Codybartfast (category 0)

With arrays containing 33M-134M items and then searching for each item I found a measurable difference in run-time with the modified version taking approx. 4% longer. The extra steps to terminate in the modified version being more expensive than the cost of the extra test in the original version.

Size OriginalModifiedDiff
2^25 4.042s4.188s3.6%
2^26 8.365s8.551s2.2%
2^27 16.854s17.818s5.7%

(Each value the is average of 3 runs.
Timings made with linux 'time' command.)

#define SIZE 1 << 25

int binsearch(int x, int v[], int n);

int values[SIZE];

int main(void)
{
	int i, n = SIZE;

	for (i = 0; i < n; i++)
		values[i] = i;
	/* search for every item */
	for (i = 0; i < n; i++)
		binsearch(i, values, n);
	return 0;
}

int binsearch(int x, int v[], int n)
{
	int low, high, mid;

	low = 0;
	high = n - 1;
	while (low < high) {
		mid = (low + high) / 2;
		if (x > v[mid])
			low = mid + 1;
		else
			high = mid;
	}
	return (x == v[low]) ? low : -1;
}
Personal tools