binary search (bsearch) with 2 keys

Hi Folks,

i´m focusing the following problem:

I want to select from the persons table the entry which matches 2 keys: FirstName & Age. However, the below code doesn´t do, it neglects the name and just regards the age as a single key. Any help would be gratful!

cheers
deSertfiSh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
struct Person
{
  char * FirstName;
  char * FamilyName;
  int    Age;
};
 
int compareAge( void const * lhs, void const * rhs )
{
  struct Person * left  = ((struct Person *) lhs);
  struct Person * right = ((struct Person *) rhs);
 
  if(strcmp(left->FirstName , right->FirstName )) 
  {
    if( left->Age < right->Age ) return -1;
    if( left->Age > right->Age ) return 1;
  }
 
  return 0;
}
 
int main ( void )
{
  struct Person figures[] = { { "Max",  "Mustermann", 40 }
                            , { "Erika", "Mustermann", 38 }
                            , { "Jane", "Doe", 32 }
                            , { "Anna", "Gabler", 38 }
                            , { "John", "Doe", 34 }
                            , { "Anna", "Mustermann", 51 }
                            , { "Ann",  "MissX", 52 }
                            , { "Anne", "Mustermann", 53 }
                            , { "Anna", "Mustermann", 54 }
                            , { "Anna", "Mustermann", 55 }
                            , NULL };
 
  int const elements = 10;
  int const ageKey   = 52;
  char* const nameKey   = "Anni";
 
  int i = 0;
  
  qsort( figures, elements, sizeof( struct Person ), compareAge );
 
  struct Person key;
  key.Age = ageKey;
  key.FirstName = nameKey;
 
  struct Person* result = (Person*) bsearch( &key, figures, elements, sizeof( struct Person ), compareAge );
 
  if( result )
    printf( "gefunden: %s, %s (%d)\n", result->FamilyName, result->FirstName, result->Age );
  else
    printf( "nichts gefunden\n" );
 
  return EXIT_SUCCESS;
}


result is:

gefunden: MissX, Ann (52)
Is your strcmp() supposed to see if these strings are equal? If so, you have it backwards. Strings are equal when strcmp() returns 0.
ok, you are right, I modified to this:
1
2
3
4
5
6
  if( strcmp(left->FirstName , right->FirstName ) == 0 )
  {
     if( left->Age == right->Age ) return 1;
  }
 
  return 0;


but anyway it doesn´t work :-(

deSertfiSh
Don't you need to see if left-Age == right->Age?
Should you get the following?

Ann 52
Anna 38
Anna 51
Anna 54
Anna 55
Anne 53
Erika 38
Jane 32
John 34
Max 40
no, I expect to be able to select 1 entry which matches

int const ageKey = 54;
char* const nameKey = "Anna"

So, i expect the result to be (f.ex.):

{ "Anna", "Mustermann", 54 }


deSertfiSh
Do not be hurry. I see that in the very beginning of your program the array is sorted. So I am asking should the array be sorted as I have shown? Have you the same sorted array before searching?
Last edited on
In any case try the following function

1
2
3
4
5
6
7
8
9
10
int compareAge( void const * lhs, void const * rhs )
{
   struct Person * left  = ( struct Person * ) lhs;
   struct Person * right = ( struct Person * ) rhs;
 
   int result = strcmp( left->FirstName, right->FirstName );

   if ( result ) return ( result );
   else return ( left->Age - right->Age );
}  
Last edited on
Hey Vlad!

spasibo bolschoi, your suggestion really worked! Thx and greetings to Moscow!

deSertfiSh
Do you speak Russian?!
Last edited on
net
I meant that you should have all three comparisons in your compareAge() function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int compareAge( void const * lhs, void const * rhs )
    {
    struct Person * left  = ((struct Person *) lhs);
    struct Person * right = ((struct Person *) rhs);
 
    int rc = strcmp( left->FirstName, right->FirstName );

    if( 0 == rc ) 
        {
        if( left->Age == right->Age )
            rc = 0;

        if( left->Age < right->Age )
            rc = -1;

        if( left->Age > right->Age )
            rc = 1;

        }    /*    if( the first names match )    */

    return rc;

    }
        /*    compareAge()    */

Last edited on
thx! I think, I got the idea now and can aplly it on my concret problem!

Thx for answering!

deSertfiSh
kooth,

that do not do three comparisions it is better to add 'else'

1
2
3
4
5
6
7
8
        if( left->Age == right->Age )
            rc = 0;

        else if( left->Age < right->Age )
            rc = -1;

        else if( left->Age > right->Age )
            rc = 1;
vlad,

Yes, I know: I was trying to get this done quickly. deSertfiSh: You're welcome!
The simplest body of the function is

1
2
3
4
5
int rc;

if ( !( rc = strcmp( left->FirstName, right->FirstName ) ) rc = left->Age - right->Age;

return ( rc );
Last edited on
Topic archived. No new replies allowed.