web-dev-qa-db-ja.com

JavaScriptのバイナリ検索

JavaScriptでバイナリ検索アルゴリズムを実装しようとしています。物事は大丈夫なようですが、私のreturnステートメントは未定義を返しているように見えますか?誰がここで何が間違っているのかわかりますか?

フィドル: http://jsfiddle.net/2mBdL/

ありがとう。

var a = [
    1,
    2,
    4,
    6,
    1,
    100,
    0,
    10000,
    3
];

a.sort(function (a, b) {
    return a - b;
});

console.log('a,', a);

function binarySearch(arr, i) {
    var mid = Math.floor(arr.length / 2);
    console.log(arr[mid], i);

    if (arr[mid] === i) {
        console.log('match', arr[mid], i);
        return arr[mid];
    } else if (arr[mid] < i && arr.length > 1) {
        console.log('mid lower', arr[mid], i);
        binarySearch(arr.splice(mid, Number.MAX_VALUE), i);
    } else if (arr[mid] > i && arr.length > 1) {
        console.log('mid higher', arr[mid], i);
        binarySearch(arr.splice(0, mid), i);
    } else {
        console.log('not here', i);
        return -1;
    }

}
var result = binarySearch(a, 100);
console.log(result);
30
4m1r

再帰的な内部呼び出し(つまりreturn binarySearch())を明示的に返さないため、呼び出しスタックは戻り値なしで展開されます。次のようにコードを更新します。

// ...
if (arr[mid] === i) {
    console.log('match', arr[mid], i);
    return arr[mid];
} else if (arr[mid] < i && arr.length > 1) {
    console.log('mid lower', arr[mid], i);
    return binarySearch(arr.splice(mid, Number.MAX_VALUE), i);
} else if (arr[mid] > i && arr.length > 1) {
    console.log('mid higher', arr[mid], i);
    return binarySearch(arr.splice(0, mid), i);
} else {
// ...

作業フィドル を参照してください

18
Eliran Malka

要素が見つからない場合、新しい要素の挿入ポイントを示す負の値を返すような方法で検索関数を作成すると便利です。また、バイナリ検索で再帰を使用することは過度で不要です。そして最後に、コンパレーター関数をパラメーターとして提供することにより、検索アルゴリズムを汎用的にすることをお勧めします。以下は実装です。

function binarySearch(ar, el, compare_fn) {
    var m = 0;
    var n = ar.length - 1;
    while (m <= n) {
        var k = (n + m) >> 1;
        var cmp = compare_fn(el, ar[k]);
        if (cmp > 0) {
            m = k + 1;
        } else if(cmp < 0) {
            n = k - 1;
        } else {
            return k;
        }
    }
    return -m - 1;
}

このコードには、コメントと単体テスト here が含まれています。

71

この質問には多くの実行可能な解決策があります。ただし一致するものが見つかると、それらはすべて早期に戻ります。これはパフォーマンスにわずかにプラスの影響を与える可能性がありますが、バイナリ検索の対数の性質によりこれは無視でき、比較関数の計算に費用がかかる場合は実際にパフォーマンスを損なう可能性があります。

さらに、バイナリ検索アルゴリズムの非常に有用なアプリケーションを防止します。lowerまたは上限

次の実装は、インデックス0iarray.lengthを返します。指定された述語は、array[i - 1]の場合はfalsearray[i]の場合はtrueです。述語がfalseである場合、array.lengthが返されます。

/**
 * Return 0 <= i <= array.length such that !pred(array[i - 1]) && pred(array[i]).
 */
function binarySearch(array, pred) {
    let lo = -1, hi = array.length;
    while (1 + lo < hi) {
        const mi = lo + ((hi - lo) >> 1);
        if (pred(array[mi])) {
            hi = mi;
        } else {
            lo = mi;
        }
    }
    return hi;
}

議論のために、pred(array[-1]) === falseおよびpred(array[array.length]) === true(もちろん、述語はそれらのポイントで評価されることはありません)と仮定します。ループは不変式!pred(array[lo]) && pred(array[hi])を維持します。アルゴリズムは、1 + lo === hi!pred(array[hi - 1]) && pred(array[hi])を意味するときに終了します。これは目的の事後条件です。

比較関数compareに関して配列がsort() edされている場合、関数はsmallestitemの位置を挿入

binarySearch(array, j => 0 <= compare(item, j));

挿入位置は、配列内にアイテムが存在する場合にアイテムが見つかるインデックスです。

自然な配列のlowerおよびupper boundの実装は簡単です次のように注文します。

/**
 * Return i such that array[i - 1] < item <= array[i].
 */
function lowerBound(array, item) {
    return binarySearch(array, j => item <= j);
}

/**
 * Return i such that array[i - 1] <= item < array[i].
 */
function upperBound(array, item) {
    return binarySearch(array, j => item < j);
}

もちろん、これは、配列に同じように比較する複数の要素を含めることができる場合、たとえば要素に並べ替え条件の一部ではない追加データが含まれる場合に最も役立ちます。

14
joki

バイナリ検索機能は次のとおりです。

   function bsearch (Arr,value){
        var low  = 0 , high = Arr.length -1 ,mid ;      
        while (low <= high){
            mid = Math.floor((low+high)/2);     
            if(Arr[mid]==value) return mid ; 
            else if (Arr[mid]<value) low = mid+1;
            else high = mid-1;          
        }
        return -1 ;
    }
9
Ashutosh Jha

これが私の解決策です!

// perform a binarysearch to find the position in the array
function binarySearch(searchElement, searchArray) {
    'use strict';

    var stop = searchArray.length;
    var last, p = 0,
        delta = 0;

    do {
        last = p;

        if (searchArray[p] > searchElement) {
            stop = p + 1;
            p -= delta;
        } else if (searchArray[p] === searchElement) {
            // FOUND A MATCH!
            return p;
        }

        delta = Math.floor((stop - p) / 2);
        p += delta; //if delta = 0, p is not modified and loop exits

    }while (last !== p);

    return -1; //nothing found

};
2
fstasi

バイナリ検索ES6

// bottom-up
function binarySearch (arr, val) {
    let start = 0;
    let end = arr.length - 1;

    while (start <= end) {
        let mid = Math.floor((start + end) / 2);

        if (arr[mid] === val) {
            return mid;
        }
        if (val < arr[mid]) {
            end = mid - 1;
        } else {
            start = mid + 1;
        }
    }
    return -1;
}

別のアプローチ:

// recursive
function binarySearch(arr, val, start = 0, end = arr.length - 1) {
    const mid = Math.floor((start + end) / 2);

    if (val === arr[mid]) {
        return mid;
    }
    if (start >= end) {
        return -1;
    }
    return val < arr[mid]
        ? binarySearch(arr, val, start, mid - 1)
        : binarySearch(arr, val, mid + 1, end);
}
2
Lior Elrom

???????????? ???????????????? ???????????????????????? ???????????????? ????????????????。

正しく実装されたバイナリ検索(配列の変更、配列のコピー、または他の不条理なし)は、O(k * log2(n))(kは不必要なオーバーヘッドを表す定数です)。 1024個の要素の配列があるとします。この場合、定数kは1です。線形検索では、平均複雑度はO(k * n/2 O(1 * 1024/2)= O(512))==になります。バイナリ検索では、O(k * log2(n) O(1 * log2(1024))= O(1 * 10)= O(10))==ここで、線形検索アルゴリズムを25%高速化し、バイナリ検索アルゴリズムを25%高速化するとします。現在、kは両方のアルゴリズムで0.75です。線形検索の複雑さはO(384)(パフォーマンスポイント128のゲイン)に減少し、バイナリ検索はO(7.5)(ゲインのみの減少) 2.5パフォーマンスポイント)。バイナリ検索方法の最適化によるこの最小限の利点は、バイナリ検索方法がすでに非常に高速であるためです。したがって、正気な人は、バイナリ検索アルゴリズムを最適化する前に、プログラムの残りの部分をより最適化する傾向があります。しかし、私は健全な人ではありません。したがって、バイナリ検索機能をJavascriptエンジニアリングの絶対的な制限に最適化しました。

パフォーマンスの最大値から始めるために、最初に最初の関数を調べてみましょう。この関数は、ページのさらに下に表示される関数よりもはるかに遅い可能性がありますが、後で完全に失われないように理解しやすくする必要があります。

const sArr = [0,4,5,6,9,13,14,21,27,44];
document.write(slowestBS(sArr, 14)); // don't use document.write in production

function slowestBS(array, searchedValue, ARG_start, ARG_len){
  // Range of [start, start+len): only start is inclusive. It works
  // similarly to "...".substr(start, len).indexOf(sValue)
  // `void 0` is shorthand for `undefined`
  var start = ARG_start |0;
  var len = (ARG_len === void 0 ? (array.length|0)-start : ARG_len) | 0;
  len = len - 1 |0;
  for (let i=0x80000000; i; i >>>= 1) {
    if (len & i) {
      const withoutCurBit = len & ~(i-1);
      if (array[start + withoutCurBit] > searchedValue) {
        len = withoutCurBit - 1 |0;
      }
    }
  }
  if (array[start+len] !== searchedValue) {
    // remove this if-statement to return the next closest
    // element going downwards from the searched-for value
    // OR 0 if the value is less than all values in the
    // array
    return -1 - start - len |0;
  }
  return start + len |0;
}

上記の関数の戻り値は次のとおりです。

  • 値が見つかった場合、値のインデックスを返します。
  • 値が見つからなかった場合は、-1 - nearestIndexを返します。nearestIndexは、見つかったインデックスで、最も近い数値<=インデックスであり、0を上限としています。
  • 配列が指定された範囲内でソートされていない場合、意味のない数値が返されます。

最適化を開始するには、まずその厄介な内部if-branchを削除しましょう。

const sArr = [0,4,5,6,9,13,14,21,27,44];
document.write(compactBS(sArr, 44)); // don't use document.write in production

function compactBS(array, searchedValue, ARG_start, ARG_len){
  // `void 0` is shorthand for `undefined`
  var start = ARG_start === void 0 ? 0 : ARG_start |0;
  var len = (ARG_len === void 0 ? (array.length|0) - start : ARG_len) |0;
  len = len - 1 | 0;
  for (let i=0x80000000; i; i >>>= 1) {
    if (len & i) {
      const noCBit = len & ~(i-1);
      // noCBits now contains all the bits in len that are
      // greater than the present value of i.
      len ^= (
        (len ^ (noCBit-1)) & 
        ((array[start+noCBit] <= searchedValue |0) - 1 >>>0)
      ); // works based on the logic that `(x^y)^x === y` is always true
    }
  }
  if (array[start+len] !== searchedValue) {
    // remove this if-statement to return the next closest
    // element going downwards from the searched-for value
    // OR 0 if the value is less than all values in the
    // array
    return -1 - start - len |0;
  }
  return start + len |0;
}

そして、今、それを展開し、事前計算し、高速で、素晴らしく、良いものにします:

const sArr = [0,4,5,6,9,13,14,21,27,44];
document.write(goodBinarySearch(sArr, 5)); // don't use document.write in
                                           //  production

function goodBinarySearch(array, sValue, ARG_start, ARG_len){
  // Range of [start, start+len): only start is inclusive. It works
  // similarly to "...".substr(start, len).indexOf(sValue)
  // `void 0` is shorthand for `undefined`
  var start = (ARG_start === void 0 ? 0 : ARG_start) | 0;
  var len = (ARG_len === void 0 ? (array.length|0) - start : ARG_len) |0;
  len = len - 1 |0;
  
  if (len & 0x80000000) {
    const nCB = len & 0x80000000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x40000000) {
    const nCB = len & 0xc0000000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x20000000) {
    const nCB = len & 0xe0000000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x10000000) {
    const nCB = len & 0xf0000000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x8000000) {
    const nCB = len & 0xf8000000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x4000000) {
    const nCB = len & 0xfc000000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x2000000) {
    const nCB = len & 0xfe000000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x1000000) {
    const nCB = len & 0xff000000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x800000) {
    const nCB = len & 0xff800000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x400000) {
    const nCB = len & 0xffc00000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x200000) {
    const nCB = len & 0xffe00000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x100000) {
    const nCB = len & 0xfff00000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x80000) {
    const nCB = len & 0xfff80000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x40000) {
    const nCB = len & 0xfffc0000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x20000) {
    const nCB = len & 0xfffe0000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x10000) {
    const nCB = len & 0xffff0000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x8000) {
    const nCB = len & 0xffff8000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x4000) {
    const nCB = len & 0xffffc000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x2000) {
    const nCB = len & 0xffffe000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x1000) {
    const nCB = len & 0xfffff000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x800) {
    const nCB = len & 0xfffff800;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x400) {
    const nCB = len & 0xfffffc00;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x200) {
    const nCB = len & 0xfffffe00;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x100) {
    const nCB = len & 0xffffff00;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x80) {
    const nCB = len & 0xffffff80;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x40) {
    const nCB = len & 0xffffffc0;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x20) {
    const nCB = len & 0xffffffe0;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x10) {
    const nCB = len & 0xfffffff0;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x8) {
    const nCB = len & 0xfffffff8;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x4) {
    const nCB = len & 0xfffffffc;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x2) {
    const nCB = len & 0xfffffffe;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x1) {
    const nCB = len & 0xffffffff;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (array[start+len|0] !== sValue) {
    // remove this if-statement to return the next closest
    // element going downwards from the searched-for value
    // OR 0 if the value is less than all values in the
    // array
    return -1 - start - len |0;
  }
  return start + len |0;
}

しかし、待ってください... asunderはさらに優れたパフォーマンスの前夜をささやきます。おそらく、タイトループでバイナリ検索を呼び出しています。そのような場合、実際に処理される最初の値を事前に計算し、パフォーマンスロードと救世主と一緒にその値にスキップすることができます:整数インデックスswitchステートメント。ただし、これを使用している間は、配列の一部のみが検索されるため、配列の長さが変更された後は、生成された高速関数を再利用しないことを確認する必要があります。

const clz32 = Math.clz32 || (function(log, LN2){
  return function(x) {
    return 31 - log(x >>> 0) / LN2 | 0; // the "| 0" acts like math.floor
  };
})(Math.log, Math.LN2);

const sArr = [0,4,5,6,9,13,14,21,27,44];
const compFunc = fastestBS(sArr);
for (let x of sArr) // don't use for-of in production
  // this statement is esoteric: a traditional for loop is always faster
  // than for-of, and even more so faster when you need the index!
  document.write(x+" is at "+compFunc(x)+"<br/>"); // don't use document.write
                                                   //  in production

function fastestBS(array, ARG_start, ARG_initLen){
  // Range of [start, start+len): only start is inclusive. It works
  // similarly to "...".substr(start, len).indexOf(sValue)
  // `void 0` is shorthand for `undefined`
  var start = ARG_start === void 0 ? 0 : ARG_start |0;
  var initLen = (ARG_initLen===void 0 ? (array.length|0)-start : ARG_initLen) |0;
  initLen = initLen - 1 |0;
  const compGoto = clz32(initLen) & 31;
  return function(sValue) {
    var len = initLen | 0;
    switch (compGoto) {
      case 0:
        if (len & 0x80000000) {
          const nCB = len & 0x80000000;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 1:
        if (len & 0x40000000) {
          const nCB = len & 0xc0000000;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 2:
        if (len & 0x20000000) {
          const nCB = len & 0xe0000000;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 3:
        if (len & 0x10000000) {
          const nCB = len & 0xf0000000;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 4:
        if (len & 0x8000000) {
          const nCB = len & 0xf8000000;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 5:
        if (len & 0x4000000) {
          const nCB = len & 0xfc000000;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 6:
        if (len & 0x2000000) {
          const nCB = len & 0xfe000000;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 7:
        if (len & 0x1000000) {
          const nCB = len & 0xff000000;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 8:
        if (len & 0x800000) {
          const nCB = len & 0xff800000;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 9:
        if (len & 0x400000) {
          const nCB = len & 0xffc00000;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 10:
        if (len & 0x200000) {
          const nCB = len & 0xffe00000;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 11:
        if (len & 0x100000) {
          const nCB = len & 0xfff00000;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 12:
        if (len & 0x80000) {
          const nCB = len & 0xfff80000;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 13:
        if (len & 0x40000) {
          const nCB = len & 0xfffc0000;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 14:
        if (len & 0x20000) {
          const nCB = len & 0xfffe0000;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 15:
        if (len & 0x10000) {
          const nCB = len & 0xffff0000;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 16:
        if (len & 0x8000) {
          const nCB = len & 0xffff8000;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 17:
        if (len & 0x4000) {
          const nCB = len & 0xffffc000;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 18:
        if (len & 0x2000) {
          const nCB = len & 0xffffe000;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 19:
        if (len & 0x1000) {
          const nCB = len & 0xfffff000;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 20:
        if (len & 0x800) {
          const nCB = len & 0xfffff800;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 21:
        if (len & 0x400) {
          const nCB = len & 0xfffffc00;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 22:
        if (len & 0x200) {
          const nCB = len & 0xfffffe00;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 23:
        if (len & 0x100) {
          const nCB = len & 0xffffff00;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 24:
        if (len & 0x80) {
          const nCB = len & 0xffffff80;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 25:
        if (len & 0x40) {
          const nCB = len & 0xffffffc0;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 26:
        if (len & 0x20) {
          const nCB = len & 0xffffffe0;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 27:
        if (len & 0x10) {
          const nCB = len & 0xfffffff0;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 28:
        if (len & 0x8) {
          const nCB = len & 0xfffffff8;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 29:
        if (len & 0x4) {
          const nCB = len & 0xfffffffc;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 30:
        if (len & 0x2) {
          const nCB = len & 0xfffffffe;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }
      case 31:
        if (len & 0x1) {
          const nCB = len & 0xffffffff;
          len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
        }

    }
    if (array[start+len|0] !== sValue) {
      // remove this if-statement to return the next closest
      // element going downwards from the searched-for value
      // OR 0 if the value is less than all values in the
      // array
      return -1 - start - len |0;
    }
    return start + len |0;
  };
}

デモ:

(function(document){"use strict";
var textarea = document.getElementById('inputbox'),
    searchinput = document.getElementById('search'),
    searchStart = document.getElementById('start'),
    searchedLength = document.getElementById('length'),
    resultbox = document.getElementById('result'),
    timeoutID = -1;
function doUpdate(){
   try {
      var txt = textarea.value.replace(/\s*\[|\]\s*/g, '').split(',');
      var arr = JSON.parse(textarea.value);
      var searchval = JSON.parse(searchinput.value);
      var textmtchs = textarea.value.match(/\s*\[|\]\s*/g);
      var start = searchStart.value || void 0;
      var sub = searchedLength.value || void 0;
      
      txt = refSort(txt, arr);
      textarea.value = textmtchs[0] +
                        txt.join(',') +
                       textmtchs[textmtchs.length-1];
      arr = JSON.parse(textarea.value);
      resultbox.value = goodBinarySearch(arr, searchval, start, sub);
   } catch(e) {
      resultbox.value = 'Error';
   }
}
textarea.oninput = searchinput.oninput = 
    searchStart.oninput = searchedLength.oninput =
    textarea.onkeyup = searchinput.onkeyup = 
    searchStart.onkeyup = searchedLength.onkeyup = 
    textarea.onchange = searchinput.onchange = 
    searchStart.onchange = searchedLength.onchange = function(e){
  clearTimeout( timeoutID );
  timeoutID = setTimeout(doUpdate, e.target === textarea ? 384 : 125);
}

function refSort(targetData, refData) {
  var indices = Object.keys(refData);
  indices.sort(function(indexA, indexB) {
    if (refData[indexA] < refData[indexB]) return -1;
    if (refData[indexA] > refData[indexB]) return 1;
    return 0;
  });
  return indices.map(function(i){ return targetData[i] })
}
function goodBinarySearch(array, sValue, ARG_start, ARG_len){
  // Range of [start, start+len): only start is inclusive. It works
  // similarly to "...".substr(start, len).indexOf(sValue)
  // `void 0` is shorthand for `undefined`
  var start = (ARG_start === void 0 ? 0 : ARG_start) | 0;
  var len = (ARG_len === void 0 ? (array.length|0) - start : ARG_len) |0;
  len = len - 1 |0;
  
  if (len & 0x80000000) {
    const nCB = len & 0x80000000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x40000000) {
    const nCB = len & 0xc0000000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x20000000) {
    const nCB = len & 0xe0000000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x10000000) {
    const nCB = len & 0xf0000000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x8000000) {
    const nCB = len & 0xf8000000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x4000000) {
    const nCB = len & 0xfc000000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x2000000) {
    const nCB = len & 0xfe000000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x1000000) {
    const nCB = len & 0xff000000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x800000) {
    const nCB = len & 0xff800000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x400000) {
    const nCB = len & 0xffc00000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x200000) {
    const nCB = len & 0xffe00000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x100000) {
    const nCB = len & 0xfff00000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x80000) {
    const nCB = len & 0xfff80000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x40000) {
    const nCB = len & 0xfffc0000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x20000) {
    const nCB = len & 0xfffe0000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x10000) {
    const nCB = len & 0xffff0000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x8000) {
    const nCB = len & 0xffff8000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x4000) {
    const nCB = len & 0xffffc000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x2000) {
    const nCB = len & 0xffffe000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x1000) {
    const nCB = len & 0xfffff000;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x800) {
    const nCB = len & 0xfffff800;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x400) {
    const nCB = len & 0xfffffc00;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x200) {
    const nCB = len & 0xfffffe00;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x100) {
    const nCB = len & 0xffffff00;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x80) {
    const nCB = len & 0xffffff80;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x40) {
    const nCB = len & 0xffffffc0;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x20) {
    const nCB = len & 0xffffffe0;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x10) {
    const nCB = len & 0xfffffff0;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x8) {
    const nCB = len & 0xfffffff8;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x4) {
    const nCB = len & 0xfffffffc;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x2) {
    const nCB = len & 0xfffffffe;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (len & 0x1) {
    const nCB = len & 0xffffffff;
    len ^= (len ^ (nCB-1)) & ((array[start+nCB|0] <= sValue |0) - 1 >>>0);
  }
  if (array[start+len|0] !== sValue) {
    // remove this if-statement to return the next closest
    // element going downwards from the searched-for value
    // OR 0 if the value is less than all values in the
    // array
    return -1 - start - len |0;
  }
  return start + len |0;
}
})(document);
<h3 style="margin:.125em;width:100%;text-align:center">The Array (Must Be A Valid JSON Array)</h3>
<textarea placeholder="[-24, -12, 0, 0, 9, 16, 18, 64, 80]" type="text" rows=6 style="width:calc(100% - .5em);display:block" id="inputbox">[-24, -12, 0, 0, 9, 16, 18, 64, 80]</textarea>

<table style="table-layout:fixed;font-size:1.2em" width="100%"><tbody>
  <tr>
    <td colspan="3">Search Value: <input type="text" id="search" value="-12" style="width:8em;text-align:center;float:right" /></td>
    <td></td>
    <td colspan="3">Resulting Index: <input type="text" id="result" value="1" style="width:8em;text-align:center;float:right" readonly="" />
  </tr>
  <tr>
    <td colspan="3">Start Index: <input type="text" id="start" value="" placeholder="(0)" style="width:8em;text-align:center;float:right" /></td>
    <td></td>
    <td colspan="3">Searched Length: <input type="text" id="length" value="" placeholder="(array length)" style="width:8em;text-align:center;float:right" />
  </tr>
</tbody></table>

デモでは文字列の配列(引用符で囲まれた)を使用することもできますが、これは正常に機能するはずです。文字列を検索するには、検索値を引用符で囲む必要があります。

1
Jack Giffin

エレガントなrecursiveを例に考えてみましょう。tailはES6標準を提供するほとんどのブラウザでパフォーマンスに影響を与えるものを呼び出します。

function binarySearch(arr, item) {
  function search(low, high) {
    if (low > high) return -1
    const mid = Math.floor((low + high)/2)
    if (arr[mid] === item) return mid
    const nextLow = item > arr[mid] ? mid+1 : low
    const nextHigh = item < arr[mid] ? mid-1 : high
    return search(nextLow, nextHigh)
  }
  return search(0, arr.length-1)
}

陽性検査:

binarySearch([2, 6, 9, 14, 21],  9) // => 2
binarySearch([2, 6, 9, 14, 21], 21) // => 4
binarySearch([2, 6, 9, 14, 21],  2) // => 0

陰性検査:

binarySearch([2, 6, 9, 14, 21],  0) // => -1
binarySearch([2, 6, 9, 14, 21], -4) // => -1
binarySearch([2, 6, 9, 14, 21], 40) // => -1
1
Purkhalo Alex

検索対象の要素のindexを返す再帰的なバイナリ検索関数:

function binarySearch(arr, target, idx=0){
  let full_len = arr.length;
  if(full_len === 0){
    return null;
  }
  let mid = Math.floor(full_len / 2);
  if(arr[mid] === target){
    return `INDEX of ${target} is: ${idx+mid}`;
  }else if(target > arr[mid]){
    let right = arr.slice(mid + 1, full_len);
    idx += (full_len - right.length);
    return binarySearch(right, target, idx);
  }else if(target < arr[mid]){
    let left = arr.slice(0, mid);
    return binarySearch(left, target, idx);
  }
}

//Testing:

var arr = [1, 27, 34, 42, 58, 69, 71, 85, 96, 151];
console.log(binarySearch(arr, 1)); //=> 0
console.log(binarySearch(arr, 27)); //=> 1
console.log(binarySearch(arr, 34)); //=> 2
console.log(binarySearch(arr, 42)); //=> 3
console.log(binarySearch(arr, 58)); //=> 4
console.log(binarySearch(arr, 69)); //=> 5
console.log(binarySearch(arr, 71)); //=> 6
console.log(binarySearch(arr, 85)); //=> 7
console.log(binarySearch(arr, 96)); //=> 8
console.log(binarySearch(arr, 151)); //=> 9
arr = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
console.log(binarySearch(arr, 10)); //=> 0
console.log(binarySearch(arr, 20)); //=> 1
console.log(binarySearch(arr, 30)); //=> 2
console.log(binarySearch(arr, 40)); //=> 3
console.log(binarySearch(arr, 50)); //=> 4
console.log(binarySearch(arr, 60)); //=> 5
console.log(binarySearch(arr, 70)); //=> 6
console.log(binarySearch(arr, 80)); //=> 7
console.log(binarySearch(arr, 90)); //=> 8
console.log(binarySearch(arr, 100)); //=> 9

var bigArr = [];
for(var i = 1; i <= 1000000; i++){
  bigArr.Push(i);
}
console.log(binarySearch(bigArr, 5342)) //=> 5341
console.log(binarySearch(bigArr, 254369)) //=> 254368
console.log(binarySearch(bigArr, 2000000)) //=> null
console.log(binarySearch(bigArr, -1)) //=> null
1
Ctpelnar1988

この問題のバリエーションは、完全に一致するものがない場合、検索Xに最も近い要素を見つけることです。

そのために、 @ Alexander Ryzhovの答え を適用して、常に「挿入ポイント」= X以上の要素の最小のインデックスを返します。

結果インデックスIを取得したら、IXまたはXより大きい場合があります)およびI-1の要素をチェックします(小さい方)、2つのうち最も近いものを選択します。 Edgeのケースを処理することを忘れないでください!

function binarySearch(a, compare) {
    let le = 0,
        ri = a.length - 1;

    while (le <= ri) {
        let mid = (le + ri) >> 1,
            cmp = compare(a[mid]);

        if (cmp > 0) {
            le = mid + 1;
        } else if (cmp < 0) {
            ri = mid - 1;
        } else {
            return mid;
        }
    }

    return le;
}


function binaryClosest(a, compare) {
    let i = binarySearch(a, compare);

    if (i === 0)
        return a[0];

    if (i === a.length)
        return a[i - 1];

    let d1 = -compare(a[i]),
        d2 = compare(a[i - 1]);

    return d1 < d2 ? a[i] : a[i - 1];
}


//

input = [-3, -2, -1, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3]
findX = x => binaryClosest(input, item => x - item)

test = (exp, arg) => {
    let x = findX(arg)
    console.log(exp === x ? 'ok' : 'FAIL', arg, exp, x)
};

test(-3, -99)
test(+3, +99)

test(0, +0.3)
test(0, 0)
test(0, -0.3)

test(-1, -1.3)
test(+1, +1.3)

test(2, 2.2)
test(2, 2.3)
test(2, 2.5)
test(3, 2.6)
1
georg

searchArray バイナリ検索関数とツールユーティリティ関数insertSortedArrayおよびremoveSortedArrayを回答のリストに追加したいと思います。グローバルな使用方法であり、非常に最適な速度だと思います。

0
ikrabbe

lodash implementation here をチェックするだけです

0
Ivan Nosov

以下のオプションは、JSでバイナリ検索を実装するのが簡単だと思います。

arr = [1,2,3,4,5];
searchTerm=2;
function binarySearchInJS(start,end)
{
    isFound=false;
    if(end > start)
    {
        //console.log(start+"\t"+end)
        mid =  (end+start)/2;

        mid = Math.floor(mid)

        if(searchTerm==arr[mid])
        {                   
              isFound = true;             
        }
        else
        {   

            if(searchTerm < arr[mid])
            {               
                binarySearchInJS(start,mid);
            }
            if(searchTerm > arr[mid])
            {           
                binarySearchInJS(mid+1,end);
            }
        }
    }

    if(isFound)
    {
        return "Success";   
    }
    else{
            return "Not Found"; 
    }       
}
0

使用するには、そのままコピーして貼り付け、速度を上げるためにローカル変数を使用します。サブオブジェクトまたは配列で検索する場合のように、検索値を変更します。

if (array[mid][0] < value[0]) low = mid + 1;
if (array[mid].val < value.val) low = mid + 1;

より高速な結果を得るには、配列または配列の配列または並列配列を使用し、検索された配列をローカル変数にコピーします。非ローカル変数、またはobj.somethingを実行するたびに速度が低下します。

これは次のような最速バージョンです。

let array=[3,4,5,6]
let value=5; //searched value
let mid, low = 0,high = array.length;
while (low < high) {
    mid = low + high >>> 1; // fast divide by 2 and round down
    if (array[mid] < value) low = mid + 1;
    else high = mid;
}
//if (array[mid] != value) mid=-1;// this might not be required if you look for place to insert new value
mid;// contains the found value position or if not found one before where it would be if it was found

バイナリ検索は次のように機能します。

|           .           |     // find middle
//option 1:
|           .     v     |     // if value on right, middle is top
            |     .     |     // so then it is like this
//option 2:                    
|     v     .           |     // if value on left, middle is bottom
|     .     |                 // so then it is like this
//more loops of option 2 until not found
|  .  |                       // next time it will be like this
|. |                          // next time it will be like this
.                             // next time it will be like this

見つからない場合、この実装は最下位になります。常に検出される場合と、常に検出されるわけではありません。検索された値以下のインデックスを返します。等しいかどうかを確認する必要があります。値が存在するか、それが以下の1つの結果であるかを検証します。宿を挿入する場所を探している場合は、その場所に置くだけで、等しいかどうかを確認する必要はありません

0
Shimon Doodkin

また、「値が見つかりません」エッジケースを確認し、それを最初の基本条件にしてから、検索を成功させる必要があります。したがって、配列を再帰的に調べるときに、配列の長さ> 1をチェックする必要はありません。最後に、配列を返さないので、Array.prototype.sliceメソッドを使用してみませんか?

var binarySearch = function(arr, val) {
  var half = Math.floor(arr.length / 2);

  if (arr.length === 0) {
    return -1;
  }
  else if (arr[half] === val) {
    console.log("val: ", val, "arr[half]: ", arr[half]);
    return val;
  }
  else if (val > arr[half]) {
    console.log("val: ", val, "arr[half]: ", arr[half]);
    return binarySearch(arr.slice(half, arr.length), val);
  }
  else {
    console.log("val: ", val, "arr[half]: ", arr[half]);
    return binarySearch(arr.slice(0, half), val);
  }
}


var arr = [1, 5, 20, 58, 76, 8, 19, 41].sort(function(a, b) { return a - b });

console.log("Sorted array: " + arr);
console.log(binarySearch(arr, 76));
console.log(binarySearch(arr, 19));
console.log(binarySearch(arr, 0));
0
adkelley

ソートされた配列を想定して、ここに再帰的なバイナリ検索があります:

function binSearch(needle, arr) {
  length = arr.length;
  while(length > 1) {
    midpoint = Math.floor(length/2);
    return (needle > arr[midpoint-1]) ? 
           binSearch(needle, arr.splice(midpoint, length)) :    
           binSearch(needle, arr.splice(0, midpoint));
  }
  return needle === arr[0] ? arr[0] : -1;
}
0
de Raad

フル機能のバイナリ検索:

  • 負の値は挿入ポイントを示します
  • 最初と最後のインデックスの検索を許可する
  • 開始インデックス、排他的終了インデックス
  • カスタム比較機能

(このコードと単体テスト ここ

function defaultCompare(o1, o2) {
    if (o1 < o2) {
        return -1;
    }
    if (o1 > o2) {
        return 1;
    }
    return 0;
}

/**
 * @param array sorted array with compare func
 * @param item search item
 * @param start (optional) start index
 * @param end (optional) exclusive end index
 * @param compare (optional) custom compare func
 * @param bound (optional) (-1) first index; (1) last index; (0) doesn't matter
 */
function binarySearch(array, item, start, end, compare, bound) {
    if (!compare) {
        compare = defaultCompare;
    }
    let from = start == null ? 0 : start;
    let to = (end == null ? array.length : end) - 1;
    let found = -1;
    while (from <= to) {
        const middle = (from + to) >>> 1;
        const compareResult = compare(array[middle], item);
        if (compareResult < 0) {
            from = middle + 1;
        }
        else if (compareResult > 0) {
            to = middle - 1;
        }
        else if (!bound) {
            return middle;
        }
        else if (bound < 0) {
            // First occurrence:
            found = middle;
            to = middle - 1;
        }
        else {
            // Last occurrence:
            found = middle;
            from = middle + 1;
        }
    }
    return found >= 0 ? found : -from - 1;
}
0
function binarySearch(arr, num, l, r){
        if( arr instanceof Array ){
        
    l = isNaN(l) ? 0 : l;
    r = isNaN(r) ? arr.length - 1: r;
    let mid = l + 1 + Math.round((r - l)/2 - 1);    
    console.log(l, r, mid, arr[mid]);
    
    if( num == arr[mid] ){ 
        console.log("found"); 
      return mid; 
    }
    
    if( typeof arr[mid] == "undefined" || l == r ){
        console.log("not found"); return -1;
    }
    
    if( num < arr[mid] ){  
        console.log("take left"); 
      return binarySearch(arr, num, l, r - mid);
    }
    
    console.log("take right");
    return binarySearch(arr, num, mid, r);
    
  }
}

console.log( binarySearch([0, 0, 1 ,1, 2, 3, 5, 6, 11], 2) );
0
Ashvin777
function binarySearch(a = [], x) {
    let length = a.length;
    if (length === 0) {
        return false;
    } else {
        let m = Math.floor(length/2);
        let y = a[m];
        if (x === y) {
            return true;
        } else if (x < y) {
            return binarySearch(a.slice(0, m), x);
        } else {
            return binarySearch(a.slice(m + 1), x);
        }
    }
}
0
Jannic Beck

このsplice実装をコードレビューで見つけたので、この実装がどれほど悪いかを明確にすることが重要だと感じています。

まず、BinarySearchはアルゴリズムですO(log(n)) in sorted arrayは、アイテムを挿入でき、ソートされた配列を持つインデックスを検索します(使用できる配列はまた、最も近いアイテムを見つけること-コメントでいくつかの質問に答えること-値を返す意味があります-クエリしているものと異なる値になる可能性があります)

splice実装では、重大な設計の失敗があります-検索アルゴリズムがクエリされた配列を変更します。データベースがあり、query _SELECT * FROM data WHERE id=1_があり、テーブルの半分が削除されたとします。 BinarySearchに渡す前に配列を複製することはあまり役に立ちませんが、次の段落でその理由を説明します。

したがって、この設計の失敗を修正し、sliceと同じように動作する新しい関数spliceを使用しますが、配列を変更しません(選択した要素を返すだけです)。アルゴリズムにはまだ大きな欠陥があります。 _n=2^m_配列の場合、mテストを作成します。最初にslice _n/2_要素から戻り、次回は_n/4_、次に_n/8_などに戻ります。これをまとめると、_n-1_要素になります。 O(n)アルゴリズムがあり、線形検索と同じくらい高速ですが、はるかに複雑です(線形検索は平均コストが_n/2_で、slice BinarySearchは_n-1_)。元のsplice実装はさらに悪い-各spliceはテーブル内の要素をさらに移動する必要があるため、最悪の場合、最初はn second _n/2_ 3番目の_n/4_ですので、最終的には_2 * n - 1_になります。これが配列の複製があまり役に立たない理由です(複製はO(n)なので、渡す前に配列を複製しないでください良い二分探索アルゴリズム)

0

これは機能プログラミングスタイルのES6関数で、指定されていない場合はデフォルトの比較関数を使用します:探している値が数値型の場合、数値比較が想定され、そうでなければ文字列比較が想定されます。

function binarySearch(arr, val, compFunc = 
    (a, b) => typeof val == 'number' ? a-b : a.localeCompare(b), i=0, j=arr.length) {
  return i >= j ? i
    : ( mid =>
          ( cmp => 
              cmp < 0 ? binarySearch(arr, val, compFunc, i, mid) 
            : cmp > 0 ? binarySearch(arr, val, compFunc, mid+1, j) 
            : mid 
          ) (compFunc(val, arr[mid]))
      ) (i + j >> 1);
}

///////// Tests ///////////////////

function check(arr, val, compFunc) {
  var fmt = JSON.stringify;
  var result = binarySearch(arr, val); // default compFunc is assumed
  console.log(`binarySearch(${fmt(arr)}, ${fmt(val)}) == ${fmt(result)}`);
  if (result > arr.length || result < 0 || !arr.length && result 
    || result < arr.length && compFunc(val, arr[result]) > 0
    || result > 0 && compFunc(val, arr[result-1]) < 0) throw "Unexpected result!!!"
}

// Tests with numeric data:
for (var val = 0; val < 12; val++)      
  check([1, 2, 4, 6, 9, 9, 10], val, (a,b) => a-b);
// Test with empty array:
check([], 12, (a,b) => a-b);
// Test with string data:
check(['abc', 'deaf', 'def', 'g'], 'dead', (a, b) => a.localeCompare(b));
0
trincot

こんにちは、この投稿はしばらく前に始まったと思いますが、議論に貢献できると思いました。

function binarySearch(array, target, max, min) {

    //Find the Midpoint between forced max and minimum domain of the array
    var mid = ((max - min) >> 1) + min;
    //alert("Midpoint Number" + mid);
    console.log(mid);
    console.log(array[mid], "target: " + target);

    if (array[mid] === target) {
        //Target Value found
        console.log('match', array[mid], target);
        //alert('match', array[mid], target);
        return mid;
    } 
    else if (mid === 0)
    {
        //All Value have been checked, and none are the target value, return sentinel value
        return -1;
    }
    else if (array[mid] > target)
    {
        //Value at Midpoint is greater than target Value, set new maximum to current midpoint
        max = mid;
        console.log('mid lower', array[mid], target);
        //alert('mid lower', array[mid], target);
        //Call binarySearch with new search domain
        return binarySearch(array, target, max, min);
    } 

    else if (array[mid] < target)
    {
        // Value at Midpoint is less than the target Value, set new minimum to current midpoint
        min = mid;
        console.log('mid higher', array[mid], target);
        //alert('mid higher', array[mid], target);

        //Call binarySearch with new search domain
        return binarySearch(array, target, max, min);
    } 

ここには改良の余地があると確信していますが、この方法は、配列のディープコピー(大規模なデータセットを操作する場合はコストのかかるアクションになる可能性があります)を実行する必要がなく、同時に配列を変更しませんどうにかして。

お役に立てば幸いです!ありがとう、ジェレミー

0
Jeremy Noel

配列がソートされていると仮定しましょう(あなた自身のソートされたアルゴリズムを書くか、単に組み込みメソッドを使用してください)

function bSearch(array,item){
  var start = 0,
  end = item.length - 1;
  var middle = Math.floor((end+start)/2);
  while(array[middle] !== item && start < end){
    if(item < array[middle]){
      end = middle-1;
     }
    else if(item > array[middle]){
      start = middle+1;
     }
     middle = Math.floor((end+start)/2);

  } 
  if(array[item]!== middle){
     console.log('notFoundMate);
     return -1;
  }
  else {
     console.log('FoundMate);
     return middle;
  }
}
0
sg28

もっと多くの実装を見ることに興味があるなら、バイナリとリニアの比較とテストページでgithubに実装しています here

0
Amgad Fahmi