If we're using LOOKUP against an unordered array then our search is linear (i.e. O(n) ). If we
insert new entries in ascending order (instead of appending to the end) we can use bsearch (from
the C run-time library) and reduce our search to O(log(n)). For arrays of less than 50 or so (SWAG),
it probably isn't worth the effort. For programs caching hundreds of items, this optimisation
can result in significant time savings. I have seen program run times go from hours to minutes
when LOOKUP (against an unordered array) is replaced with bsearch (against an ordered
array).
d $I s 5i 0 Inz(1) d $J s Inz(0) Like($I) d item s 10a d @items s Dim(5000) Like(item) d szItem s 5i 0 Inz(%Size(item))
* * internal procedures * d insertItem pr d findItem pr 5i 0 d bSearchComp pr 10i 0 d * Value d * Value * * external procedures (from the C run-time library) * d bsearch pr * ExtProc('bsearch') d * Value d * Value d 10i 0 Value d 10i 0 Value d * Value ProcPtr d memcmp pr 10i 0 ExtProc('memcmp') d * Value d * Value d 10i 0 Value d memmove pr ExtProc('memmove') d * Value d * Value d 10i 0 Value
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * insert item into array * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * p insertItem b d pi /free // // if item not found // If (*NULL = bsearch( %Addr(item) : %Addr(@item) : $J : szItem : %PAddr('BSEARCHCOMP') ) ); $I = 1; DoW ( $I <= $J And item > @item($I) ); $I = $I + 1; EndDo; If ($I > $J ); // goes on end $J = $I; @items($J) = item; Else; // // scooch elements greater than item to the right ... // memmove( %Addr(@items($I)) + szItem : %Addr(@items($I)) : ($J - $I + 1) * szItem ); // // ... and insert the new element // @items($I) = item; $J = $J + 1; EndIf; EndIf; Return; /end-free p insertItem e
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ... Find item ... * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * p findItem b d pi 5i 0 d @ s * /free @ = bsearch( %Addr(item) : %Addr(@item) : $J : szItem : %PAddr('BSEARCHCOMP') ); If ( @ <> *NULL ); Return ((@ - %Addr(@item))/szItem) + 1; // array element Else; Return 0; EndIf; /end-free p findItem e
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ... bsearch compare ... * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * p bSearchComp b d pi 10i 0 d a@ * Value d b@ * Value /free return memcmp( a@ : b@ : szItem ); /end-free p bSearchComp e