最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

arrays - Javascript Binary SearchInsertion Performance - Stack Overflow

programmeradmin3浏览0评论
function binarySearch(value)
{
    var startIndex = 0,
        stopIndex = words.length - 1,
        middle = Math.floor((stopIndex + startIndex) / 2);

    while (words[middle] != value && startIndex < stopIndex) {
        // adjust search area
        if (value < words[middle]) {
            stopIndex = middle - 1;
        } else if (value > words[middle]) {
            startIndex = middle + 1;
        }

        // recalculate middle
        middle = Math.floor((stopIndex + startIndex) / 2);
    }
}

I am making a large list of words in the format of an array:

e.g. ["a","ab","abc","b"]

In alphabetical order. The problem I'm having is modifying my binary search algorithm to add the word in the correct place and then update?

Whats the best way performance-wise to add a word into an ordered array? And why is it the best way to do it?

function binarySearch(value)
{
    var startIndex = 0,
        stopIndex = words.length - 1,
        middle = Math.floor((stopIndex + startIndex) / 2);

    while (words[middle] != value && startIndex < stopIndex) {
        // adjust search area
        if (value < words[middle]) {
            stopIndex = middle - 1;
        } else if (value > words[middle]) {
            startIndex = middle + 1;
        }

        // recalculate middle
        middle = Math.floor((stopIndex + startIndex) / 2);
    }
}

I am making a large list of words in the format of an array:

e.g. ["a","ab","abc","b"]

In alphabetical order. The problem I'm having is modifying my binary search algorithm to add the word in the correct place and then update?

Whats the best way performance-wise to add a word into an ordered array? And why is it the best way to do it?

Share Improve this question edited Mar 10 at 13:25 WhiteHat 61.3k7 gold badges53 silver badges136 bronze badges asked Sep 11, 2012 at 12:33 LemexLemex 3,80414 gold badges56 silver badges88 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 6

For an efficient binary search insertion, you'll want to have your binary search return something that indicates where the string would belong in the array if it is not found.

The accepted method of doing this in other languages is to return the bitwise plement of the index where the string belongs. The bitwise plement of 0 is -1, the bitwise plement of 1 is -2, 2 is -3, and so on. To get the bitwise plement of a number in JavaScript, use the ~ operator.

Example code:

/* 
    target: the object to search for in the array
    parator: (optional) a method for paring the target object type
    return value: index of a matching item in the array if one exists, otherwise the bitwise plement of the index where the item belongs
*/
Array.prototype.binarySearch = function (target, parator) {
    var l = 0,
        h = this.length - 1,
        m, parison;
    parator = parator || function (a, b) {
        return (a < b ? -1 : (a > b ? 1 : 0)); /* default parison method if one was not provided */
    };
    while (l <= h) {
        m = (l + h) >>> 1; /* equivalent to Math.floor((l + h) / 2) but faster */
        parison = parator(this[m], target);
        if (parison < 0) {
            l = m + 1;
        } else if (parison > 0) {
            h = m - 1;
        } else {
            return m;
        }
    }
    return~l;
};

You can then use the binarySearch method to write your own binaryInsert function:

/*
    target: the object to insert into the array
    duplicate: (optional) whether to insert the object into the array even if a matching object already exists in the array (false by default)
    parator: (optional) a method for paring the target object type
    return value: the index where the object was inserted into the array, or the index of a matching object in the array if a match was found and the duplicate parameter was false 
*/
Array.prototype.binaryInsert = function (target, duplicate, parator) {
    var i = this.binarySearch(target, parator);
    if (i >= 0) { /* if the binarySearch return value was zero or positive, a matching object was found */
        if (!duplicate) {
            return i;
        }
    } else { /* if the return value was negative, the bitwise plement of the return value is the correct index for this object */
        i = ~i;
    }
    this.splice(i, 0, target);
    return i;
};

Once these methods are prototyped onto the array object, you can use them directly like so:

var arr = [];
arr.binaryInsert("Zebra");
arr.binaryInsert("Aardvark");
arr.binaryInsert("Mongoose");
alert(arr);
/* [ "Aardvark", "Mongoose", "Zebra" ] */

As the number of items increases, this will be signficantly faster than calling Array.sort()

Array Property Key Pollution

Note that prototyping methods onto the Array object as in the above code causes the methods to appear as enumerable properties of your arrays, which could interfere with any logic where you're enumerating all properties in a for(var i in arr) loop. Loops written in the format of for(var i=0; i<arr.length; i++) will still work as designed.

If you don't need to support Internet Explorer 8 or below, you can avoid calling Array.prototype directly and instead use Object.defineProperty as in the below examples.

Object.defineProperty(Array.prototype, "binarySearch", {
value: function (target, parator) {
    var l = 0,
        h = this.length - 1,
        m, parison;
    parator = parator || function (a, b) {
        return (a < b ? -1 : (a > b ? 1 : 0));
    };
    while (l <= h) {
        m = (l + h) >>> 1;
        parison = parator(this[m], target);
        if (parison < 0) {
            l = m + 1;
        } else if (parison > 0) {
            h = m - 1;
        } else {
            return m;
        }
    }
    return~l;
}
});

Object.defineProperty(Array.prototype, "binaryInsert", {
value: function (target, duplicate, parator) {
    var i = this.binarySearch(target, parator);
    if (i >= 0) {
        if (!duplicate) {
            return i;
        }
    } else {
        i = ~i;
    }
    this.splice(i, 0, target);
    return i;
}
});

This approach will avoid polluting the enumerable keys, so for(var i in arr) loops will still work as expected.

The best way is to use trees instead, since for an array such an operation is likely to have linear algorithmic plexity.

If you'd like to stick with the arrays, I suggest that you use the splice method for insertion.

发布评论

评论列表(0)

  1. 暂无评论