cbsearch

How to find the insertion point in an array bsearch() works on?


using bsearch() in C (standard library) one can quickly find an entry in a sorted array.

However, how do I calculate where to insert a new entry (using the standard library)?

bsearch() specifically checks whether the found item's key is equal to the passed key and if it isn't, it returns NULL - so can't use that.


Solution

  • Its not clear from the question but possibly this is what you want:

    You can do something like this to find the index in the array where bsearch () found the match.

    if (bsearch_returned_address != NULL)
      index = (bsearch_returned_address - array_base_address)
    

    EDIT

    To know the location which the bsort last visited, check the below stuff out.

    The good thing is that the manual says:

    The compar routine is expected to have two arguments which point to the key object and to an array member, in that order, and should return an integer less than, equal to, or greater than zero if the key object is found, respectively, to be less than, to match, or be greater than the array member.

    Therefore you can store the second argument inside the comparison function in a global variable, and in a case of the fail use the address in this variable, which points to the last location the bsearch function visited to find for a match.

    For example:

    A list with address and value:

    [0x8d6010: 0][0x8d6014: 4][0x8d6018: 8][0x8d601c: 12][0x8d6020: 16][0x8d6024: 20][0x8d6028: 24][0x8d602c: 28][0x8d6030: 32][0x8d6034: 36]
    

    Value to search

    13
    

    output

    fmem: (nil)  //this is the memory location where it was found
    last_mem1: 0x7fff8c8e6c54 //last val of 1st param of compare
    last_mem2: 0x8d601c //last val of 2nd param of compare
    *last_mem1: 13,        *last_mem2: 12
    

    The sample compare function code is

    static const int *last_mem1, *last_mem2;
    
    static int
    compmi(const void *a, const void *b)
    {
        last_mem1 = a; last_mem2 = b;
        return *(int *)a - *(int *)b;
    }
    

    So you can insert after the address in last_mem2. Although there are terminal cases, if you find a key which is less than the first element, then last_mem2 will also have the address of the first element.

    But how ever you have to shift the array elements to make place for the insertion, which will make the insertion complexity to O(n). You might want to improve performance by introducing some kind of lazy insertion, like make a separate unordered list, which is much smaller than your original list, and dump new elements there. When searching, perform bsearch in original list, and linear search in the dump. When the dump list grows past a certain threshold, you can merge the list by performing an insertion sort. But still, you can't be O(lg n).