Thread: Binary search on a sorted list

  1. #1
    Registered User
    Join Date
    Oct 2009
    Posts
    15

    Binary search on a sorted list

    Hi everybody,

    I'm working on a program where I'm given a sorted list of integers, and I am supposed to take an input from the user. Once I get that, I need to find the first array index of where the input occurs and the total number of occurrences. I have it pretty much finished, but I am having a problem with the logic. I have some sort of logic problem because when I prompt the user for an input,and say the user types 4, then the outputs for # of occurrence and location of first occurrence are garbage values.

    I get:

    Code:
    Please input the integer you would like to find.
    4
    The first index is -1075300456.
    The total number of values is 12169204.
    This revolves around the issue I had with the last two parameters in my function. At the bottom, in the function definition, I want count to be the total number of occurrences found in the list.

    Here is my code:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stddef.h>
    
    /* function prototype */
    
    int get_num_of_ints( const int* arr, size_t r, int N, size_t f, size_t count );
    
    int main()
    {	
    	int i;
    	int N; 										/* input variable */
    	int arr[]={1,1,2,3,4,4,4,4,5,5,6,7,7,7,7,8,9,9};					/* array of sorted integers */
    	size_t r = sizeof(arr)/sizeof(arr[0]) - 1;					/* right bound */
    	size_t f;										/* first match index */
    	size_t count;										/* total number of matches */
    		
    
    	printf( "\nPlease input the integer you would like to find.\n" );
    	scanf( "%d", &N );
    	
    	int a = get_num_of_ints( arr, r, N, f, count );
    	
    	if( a == -1)	
    	printf( "%d has not been found.\n", N );
    	
    	else if(a >= 0){
    	printf( "The first index is %d.\n", f );
    	printf( "The total number of values is %d.\n", count );
    	}
    	
    		
    	return 0;
    }
    
    /* function definition */
    
    int get_num_of_ints( const int* arr, size_t r, int N, size_t f, size_t count )
    {
    	int l = 0;
    	int m;
    	int w=r;
    	size_t* fPtr;
    	fPtr = &f;
    	size_t* countPtr;
    	countPtr = &count;	
    
    	while(l <= r){
    		m = l +(r - l)/2;
    		if(arr[m] < N)
    			l = m+1;
    		else if(arr[m] > N)
    			r = m-1;
    		else if(arr[m]==N){
    			m=m;
    			break;
    		}
    	}
    	if( l > r)
    		m = -1;
    		
    	if( m >= 0 ){	
    
    		int j = m-1;
    		int L = 0;
    
    		while( j >= 0 && arr[j] == arr[m] ){
    			L++;
    			j--;
    		}
    
    		
    		if( j>= 0 && L > 0 )
    			*fPtr=j;
    		else
    			*fPtr=m;
    	
    		int h = m + 1;
    		int R = 0;
    	
    		while( arr[h]==arr[m] && h <= w ){
    			R++;
    			h++;
    		}
    
    		
    			
    
    		*countPtr = (R + L + 1);
    		return f;
    	}
    	
    	else if( m==-1)
    		return -1;
    }
    I can't explain things completely, but when I write printf statements for L and R, they output the correct numbers. However, when they are summed together for count, I get the garbage values listed above. I cannot figure out why. I think I need to do something like the following: "Store the sum of L and R as the value at the memory location of count," but I cannot get that to work. UGGGGGGGGHHHH.

    Please help.

  2. #2
    Registered User
    Join Date
    Oct 2006
    Location
    Canada
    Posts
    1,243
    I've only quickly looked at your description and code. I imagine this is the source of your problems (I have omitted irrelevant code):
    Code:
    //...
    	size_t f;										/* first match index */
    	size_t count;										/* total number of matches */
    //...	
    	int a = get_num_of_ints( arr, r, N, f, count );
    //...
    	printf( "The first index is %d.\n", f );
    	printf( "The total number of values is %d.\n", count );
    You're declaring primitive type local variables "f" and "count". These are then passed by value to the function, which modifies the copy of these variables. So when the function returns to main, these variables "f" and "count" are uninitialized. To solve that problem, look up how to pass by reference. All primitive types that you pass to the function that you modify should be passed by reference (from the looks of it, just the two "f" and "count" should be by ref).

    Hope it helps

  3. #3
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    I see you're finding one match, then counting up with L, and down with R, and adding them together for your count.

    Just send count via it's address, instead of via copy, and you should be there, as Nadroj suggested above.

  4. #4
    Registered User
    Join Date
    Oct 2009
    Posts
    15
    Thanks guys! I was able to figure it out. I'll post my code tomorrow. I'm tidying it up right now. I kind of fell upon the solution by accident. The whole "passing by reference vs. passing by value" stuff still causes me a lot of trouble. I have to work on this a lot more.

  5. #5
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    It's really simple. C *ALWAYS* passes by copy mode.

    It *JUST SO HAPPENS* that a copy of an address, is well - perfectly good, and indistinguishable from an original address. 221 B Baker Street, is still the home of Sherlock Holmes, no matter how many times you copy that address.

    So an address is what you want when you are passing by "reference" <wink wink>, and a name is fine for passing a copy, to a function.

  6. #6
    Registered User
    Join Date
    Oct 2009
    Posts
    15

    Seg Fault

    Okay, here is my code. Unfortunately I get a seg fault on line 50 where this comparison is made for inputs less than or equal to zero:

    Code:
    if(arr[m] < N)

    And here is my code:


    Code:
    
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stddef.h>
    
    /* function prototype */
    
    int get_num_of_ints( const int* arr, size_t r, int N, size_t* f, size_t* count );
    
    int main()
    {	
    	int i;
    	int N; 										/* input variable */
    	int arr[]={1,1,2,3,4,4,4,4,5,5,6,7,7,7,7,8,9,9};					/* array of sorted integers */
    	size_t r = sizeof(arr)/sizeof(arr[0]) - 1;					/* right bound */
    	size_t f;										/* first match index */
    	size_t count;										/* total number of matches */
    		
    
    	printf( "\nPlease input the integer you would like to find.\n" );
    	scanf( "%d", &N );
    	
    	int a = get_num_of_ints( arr, r, N, &f, &count );
    	
    	if( a == -1)	
    	printf( "%d has not been found.\n", N );
    	
    	else if(a >= 0){
    	printf( "The first match index is %d.\n", f );
    	printf( "The total number of instances is %d.\n", count );
    	}
    	
    		
    	return 0;
    }
    
    /* function definition */
    
    int get_num_of_ints( const int* arr, size_t r, int N, size_t* f, size_t* count )
    {
    	int l=0;
    	int m;
    	int w=r;
    	
    
    	while(l <= r){
    		m = l +(r - l)/2;
    		if(arr[m] < N)
    			l = m+1;
    		else if(arr[m] > N)
    			r = m-1;
    		else if(arr[m]==N){
    			m=m;
    			break;
    		}
    	}
    	if( l > r)
    		m = -1;
    
    	printf( "M is %d\n", m );
    		
    	if( m >= 0 ){	
    
    		int j = m-1;
    		int L = 0;
    
    		while( j >= 0 && arr[j] == arr[m] ){
    			L++;
    			j--;
    		}
    		printf( "J is %d\n", j ); 
    		
    		if( j> 0 && L > 0 )
    			*f=j+1;
    		else if( j <= 0 )
    			*f=0;
    		else if( L==0 )
    			*f=m;
    	
    		int h = m + 1;
    		int R = 0;
    	
    		while( arr[h]==arr[m] && h <= w ){
    			R++;
    			h++;
    		}
    
    		printf( "L is %d and R is %d.\n", L, R );
    			
    
    		*count = (R + L + 1);
    		return *f;
    	}
    	
    	else if( m==-1)
    		return -1;
    }
    I dont' see why the comparison should matter or cause problems.
    Last edited by littlefermat245; 01-24-2010 at 08:40 PM.

  7. #7
    Registered User
    Join Date
    Oct 2006
    Location
    Canada
    Posts
    1,243
    Code:
    		m = l +(r - l)/2;
    		if(arr[m] < N)
    A quick guess is that 'm' is either very large or very small. Add a simple "printf" in between these two lines, showing what the values for the variables are (m, l, r). You would get a segfault if you're trying to access memory that you arent allowed to.

  8. #8
    Registered User
    Join Date
    Oct 2009
    Posts
    15
    Hmk. Yeah, my printf statemetn shows up right before the while loop, but not after. GDB says the problem is with the lines you mentioned. Do you know how I could fix that?

  9. #9
    Registered User
    Join Date
    Oct 2006
    Location
    Canada
    Posts
    1,243
    Well what does GDB say the problem is? Also, are the values of these variables correct when you run it? Tell me your sample input (i.e. the number you want to find) and the values of these 3 variables when you run it. Does it segfault on the first iteration, i.e. the first time this line is executed?

    Also, confirm you're running this exact code above, so we are in synch and not wasting my (or your) time.

  10. #10
    Registered User
    Join Date
    Oct 2009
    Posts
    15
    Yep this is my code. I added the printf statement here:

    Code:
    while(l <= r){
    		m = l +(r - l)/2;
    		printf( "This works!\n" );
    		if(arr[m] < N)
    			l = m+1;
    		else if(arr[m] > N)
    			r = m-1;
    		else if(arr[m]==N){
    			m=m;
    			break;
    		}
    	}
    I take an input like N = -6, and I get the following output w/ the statement from the debugger:

    Code:
    Please input the integer you would like to find.
    -6
    This works!
    This works!
    This works!
    This works!
    This works!
    This works!
    This works!
    
    Program received signal SIGSEGV, Segmentation fault.
    0x08048526 in get_num_of_ints (arr=0xbfe5c5cc, r=1073741822, N=-6, f=0xbfe5c5c8, count=0xbfe5c5c4) at test.c:52
    52                      if(arr[m] < N)
    (gdb) bt
    #0  0x08048526 in get_num_of_ints (arr=0xbfe5c5cc, r=1073741822, N=-6, f=0xbfe5c5c8, count=0xbfe5c5c4) at test.c:52
    #1  0x0804848f in main () at test.c:25
    (gdb)

  11. #11
    Registered User
    Join Date
    Oct 2009
    Posts
    15
    Okay I changed it to the following:


    Code:
            int l=0;
    	int m=0;
    	int w=r;
    	printf( "M is %d L is %d and R is %d\n", m, l, r );
    
    	while(l <= r){
    		m = l +(r - l)/2;
    		printf( "M is %d L is %d and R is %d", m, l, r );
    		if(arr[m] < N)
    			l = m+1;
    		else if(arr[m] > N)
    			r = m-1;
    		else if(arr[m]==N){
    			m=m;
    			break;
    		}
    	}
    	if( l > r)
    		m = -1;
    Now if I run N = 5,

    I get:

    Code:
    Please input the integer you would like to find.
    5
    M is 0 L is 0 and R is 17
    M is 8 L is 0 and R is 17M is 8
    J is 7
    L is 0 and R is 1.
    The first match index is 8.
    The total number of instances is 2.
    Seems fine.

    If I try N = -5, I get:

    Code:
    Please input the integer you would like to find.
    -5
    M is 0 L is 0 and R is 17
    M is 8 L is 0 and R is 17
    M is 3 L is 0 and R is 7
    M is 1 L is 0 and R is 2
    M is 0 L is 0 and R is 0
    M is 2147483647 L is 0 and R is -1
    M is 1073741823 L is 0 and R is 2147483646
    M is 536870911 L is 0 and R is 1073741822
    So the values just explode. I'm not sure how to get around that.

  12. #12
    Registered User
    Join Date
    Oct 2009
    Posts
    15
    Hm. Perhaps I need to change my while loop condition.

  13. #13
    Registered User
    Join Date
    Oct 2006
    Location
    Canada
    Posts
    1,243
    The type of variable "r" is "size_t", which is of type "unsigned int". Therefore, you should never get a negative value for r, but in your output you are. Try and change the type of "r" in the definition and prototype of "get num of ints" from "size_t" to "int".

  14. #14
    Registered User
    Join Date
    Mar 2009
    Posts
    48
    Code:
    M is 0 L is 0 and R is 0
     /* And code after that says */ 
    m = l +(r - l)/2;
    In the above expression , the datatype of r is size_t which rightly interprets the result as a large positive number( 0 - 1 = UINT_MAX - 1), but m is an int an implicit casting occurs and which interprets this large positive integer divided by 2 which is in the range of int, thus you get a large value of m which can be displayed by %d format.

    Since r is of type size_t which is certainly unsigned ,the value you get in m is (2 ^32 - 1) / 2.The negative answers in printf are due to the use of %d instead of %u.
    Last edited by zalezog; 01-25-2010 at 03:53 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. help! Placement of nodes in a Linked List
    By lostmyshadow in forum C Programming
    Replies: 6
    Last Post: 12-17-2007, 01:21 PM
  2. Big help in Astar search code...
    By alvifarooq in forum C++ Programming
    Replies: 6
    Last Post: 09-24-2004, 11:38 AM
  3. Request for comments
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 15
    Last Post: 01-02-2004, 10:33 AM
  4. Contest Results - May 27, 2002
    By ygfperson in forum A Brief History of Cprogramming.com
    Replies: 18
    Last Post: 06-18-2002, 01:27 PM
  5. 1st Class LIST ADT
    By Unregistered in forum C++ Programming
    Replies: 1
    Last Post: 11-09-2001, 07:29 PM