rewritten binSearch(...) impementation, still needs testing...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2013-05-19 17:26:53 +04:00
parent e7196b76e9
commit 46c3164271

View File

@ -86,8 +86,8 @@ function imageNameCmp(a, b, data){
// //
// This will return: // This will return:
// - 0 if a is equal to position i // - 0 if a is equal to position i
// - -1 if a is less position i // - -1 if a is less than position i
// - +1 if a is greater position i // - +1 if a is greater than position i
// //
// NOTE: the signature is different from the traditional cmp(a, b) so as // NOTE: the signature is different from the traditional cmp(a, b) so as
// to enable more complex comparisons involving adjacent elements // to enable more complex comparisons involving adjacent elements
@ -113,9 +113,15 @@ function cmp(a, i, lst){
// //
// NOTE: this is here mostly to make debuging easy... // NOTE: this is here mostly to make debuging easy...
function isBetween(a, i, lst){ function isBetween(a, i, lst){
//console.log('>>>', a, i, lst)
var b = lst[i] var b = lst[i]
// special case: tail...
if(i == lst.length-1 && a >= b){
return 0
}
var c = lst[i+1] var c = lst[i+1]
// hit... // hit...
if(a == b || (a > b && a < c)){ if(a == b || (a > b && a < c)){
return 0 return 0
@ -130,18 +136,8 @@ function isBetween(a, i, lst){
// Basic liner search... // Basic liner search...
function linSearch(target, lst, check, return_position, disable_direct_indexing){ function linSearch(target, lst, check, return_position){
// XXX is this the correct default? check = check == null ? cmp : check
check = check == null ? isBetween : check
// special case: target in the list directly...
if(disable_direct_indexing
&& check(target, lst.indexOf(target), lst) == 0){
return target
}
// special case: tail...
if(check(target, lst.length-1, lst) >= 0){
return lst[lst.length-1]
}
for(var i=0; i < lst.length; i++){ for(var i=0; i < lst.length; i++){
if(check(target, i, lst) == 0){ if(check(target, i, lst) == 0){
@ -152,78 +148,88 @@ function linSearch(target, lst, check, return_position, disable_direct_indexing)
// no hit... // no hit...
return return_position ? -1 : null return return_position ? -1 : null
} }
Array.prototype.linSearch = function(target, cmp){
return linSearch(target, this, cmp, true)
}
// Basic binary search implementation... // Basic binary search implementation...
// //
// NOTE: this will return the object by default, to return position set // NOTE: this will return the object by default, to return position set
// return_position to true. // return_position to true.
// NOTE: by default this will use isBetween as a predicate. // NOTE: by default this will use cmp as a predicate.
// NOTE: this still depends on .indexOf(...), to disable set function binSearch(target, lst, check, return_position){
// disable_direct_indexing to true check = check == null ? cmp : check
// XXX BUGGY var h = 0
// XXX this is a mess, needs revision... var t = lst.length - 1
function binSearch(target, lst, check, return_position, disable_direct_indexing){ var m, res
// XXX is this the correct default?
check = check == null ? isBetween : check
// special case: target in the list directly...
if(disable_direct_indexing
&& check(target, lst.indexOf(target), lst) == 0){
return target
}
// special case: tail...
if(check(target, lst.length-1, lst) >= 0){
return lst[lst.length-1]
}
// special case: head...
var res = check(target, 0, lst)
if(res == 0){
return lst[0]
} else if(res < 0){
// no hit...
return return_position ? -1 : null
}
var l = Math.ceil(lst.length/2) while(h <= t){
var i = l m = Math.floor((h + t)/2)
res = check(target, m, lst)
// match...
if(res == 0){
return return_position ? m : lst[m]
while(l > 0){ // below...
// XXX this is a hack -- should we reach 0 using floor(..) instead?
l = l <= 1 ? 0 : Math.ceil(l/2)
res = check(target, i, lst)
// right branch...
if(res > 0){
i += l
// left branch...
} else if(res < 0){ } else if(res < 0){
i -= l t = m - 1
// hit...
// above...
} else { } else {
return return_position ? i : lst[i] h = m + 1
} }
} }
// no hit...
// no result...
return return_position ? -1 : null return return_position ? -1 : null
} }
Array.prototype.binSearch = function(target, cmp){
return binSearch(target, this, cmp, true)
}
function match(f0, f1){
return function(){
var a = f0.apply(f0, arguments)
var b = f1.apply(f1, arguments)
if(a != b){
console.warn('Result mismatch: f0:'+a+' f1:'+b)
}
return a
}
}
// Same as getImageBefore, but uses gids and searches in DATA... // Same as getImageBefore, but uses gids and searches in DATA...
//
// NOTE: this uses it's own predicate...
function getGIDBefore(gid, ribbon, search){ function getGIDBefore(gid, ribbon, search){
search = search == null ? linSearch : search search = search == null ? binSearch : search
//search = search == null ? match(linSearch, binSearch) : search
ribbon = DATA.ribbons[ribbon] ribbon = DATA.ribbons[ribbon]
var order = DATA.order var order = DATA.order
var target = order.indexOf(gid) var target = order.indexOf(gid)
return search(target, ribbon, function (a, i, lst){ return search(target, ribbon, function(a, i, lst){
var b = order.indexOf(lst[i]) var b = order.indexOf(lst[i])
// special case: tail...
if(i == lst.length-1 && a >= b){
return 0
}
var c = order.indexOf(lst[i+1]) var c = order.indexOf(lst[i+1])
// hit... // hit...
if(a == b || (a > b && a < c)){ if(a == b || (a > b && a < c)){
return 0 return 0
// before... // before...
} else if(a < b){ } else if(a < b){
return -1 return -1
// later... // later...
} else { } else {
return 1 return 1