Skip to content

Commit

Permalink
Replacing the insert method in sorting.
Browse files Browse the repository at this point in the history
It has been replaced with a binary search, instead of
an insertion-sort O(n^2) search.
  • Loading branch information
jagill authored and glasser committed May 7, 2013
1 parent aa83b9d commit 8e0cf9c
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 9 deletions.
39 changes: 30 additions & 9 deletions packages/minimongo/minimongo.js
Original file line number Diff line number Diff line change
Expand Up @@ -694,21 +694,42 @@ LocalCollection._findInOrderedResults = function (query, doc) {
throw Error("object missing from query");
};

//This binary search puts a value between any equal values, and the first
//lesser value. This is to match the previous insertion behaviour of comparing
//each element and inserting it as soon as it compares less than the
//encountered value.
LocalCollection._binarySearch = function (cmp, array, value) {
if (array.length == 0) return 0;
lower = 0;
upper = array.length - 1;

while (lower <= upper) {
idx = Math.floor( (lower + upper) / 2 );
comparison = cmp(value, array[idx]);
//console.log("lower:"+lower + " upper:" + upper + " idx:"+idx +" c:"+comparison);
if (lower == upper) {
if (comparison >= 0) idx++;
return idx;
}

if ( comparison < 0 )
upper = idx;
else
lower = idx + 1;
}

return idx;
}

LocalCollection._insertInSortedList = function (cmp, array, value) {
if (array.length === 0) {
array.push(value);
return 0;
}

for (var i = 0; i < array.length; i++) {
if (cmp(value, array[i]) < 0) {
array.splice(i, 0, value);
return i;
}
}

array.push(value);
return array.length - 1;
idx = LocalCollection._binarySearch (cmp, array, value)
array.splice(idx, 0, value);
return idx;
};

// To track what documents are affected by a piece of code, call saveOriginals()
Expand Down
62 changes: 62 additions & 0 deletions packages/minimongo/minimongo_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -1048,6 +1048,68 @@ Tinytest.add("minimongo - array sort", function (test) {
_.range(c.find().count()));
});

Tinytest.add("minimongo - binary search", function (test) {
var forward_cmp = function (a, b) {
if (a < b)
return -1;
else if (b < a)
return 1;
else
return 0;
};

var backward_cmp = function (a, b) {
return -1 * forward_cmp(a, b);
};

var check_search = function (cmp, array, value, expected, message) {
actual = LocalCollection._binarySearch(cmp, array, value);
if (expected != actual) {
test.fail({type: "minimongo-binary-search",
message: message + " : Expected index " + expected +
" but had " + actual
});
}
};

var check_search_forward = function (array, value, expected, message) {
check_search(forward_cmp, array, value, expected, message);
}
var check_search_backward = function (array, value, expected, message) {
check_search(backward_cmp, array, value, expected, message);
}

check_search_forward([1, 2, 5, 7], 4, 2, "Inner insert");
check_search_forward([1, 2, 3, 4], 3, 3, "Inner insert, equal value");
check_search_forward([1, 2, 5], 4, 2, "Inner insert, odd length");
check_search_forward([1, 3, 5, 6], 9, 4, "End insert");
check_search_forward([1, 3, 5, 6], 0, 0, "Beginning insert");
check_search_forward([1], 0, 0, "Single array, less than.");
check_search_forward([1], 1, 1, "Single array, equal.");
check_search_forward([1], 2, 1, "Single array, greater than.");
check_search_forward([], 1, 0, "Empty array");
check_search_forward([1, 1, 1, 2, 2, 2, 2], 1, 3, "Highly degenerate array, lower");
check_search_forward([1, 1, 1, 2, 2, 2, 2], 2, 7, "Highly degenerate array, upper");
check_search_forward([2, 2, 2, 2, 2, 2, 2], 1, 0, "Highly degenerate array, lower");
check_search_forward([2, 2, 2, 2, 2, 2, 2], 2, 7, "Highly degenerate array, equal");
check_search_forward([2, 2, 2, 2, 2, 2, 2], 3, 7, "Highly degenerate array, upper");

check_search_backward([7, 5, 2, 1], 4, 2, "Backward: Inner insert");
check_search_backward([4, 3, 2, 1], 3, 2, "Backward: Inner insert, equal value");
check_search_backward([5, 2, 1], 4, 1, "Backward: Inner insert, odd length");
check_search_backward([6, 5, 3, 1], 9, 0, "Backward: Beginning insert");
check_search_backward([6, 5, 3, 1], 0, 4, "Backward: End insert");
check_search_backward([1], 0, 1, "Backward: Single array, less than.");
check_search_backward([1], 1, 1, "Backward: Single array, equal.");
check_search_backward([1], 2, 0, "Backward: Single array, greater than.");
check_search_backward([], 1, 0, "Backward: Empty array");
check_search_backward([2, 2, 2, 2, 1, 1, 1], 1, 7, "Backward: Degenerate array, lower");
check_search_backward([2, 2, 2, 2, 1, 1, 1], 2, 4, "Backward: Degenerate array, upper");
check_search_backward([2, 2, 2, 2, 2, 2, 2], 1, 7, "Backward: Highly degenerate array, upper");
check_search_backward([2, 2, 2, 2, 2, 2, 2], 2, 7, "Backward: Highly degenerate array, upper");
check_search_backward([2, 2, 2, 2, 2, 2, 2], 3, 0, "Backward: Highly degenerate array, upper");

});

Tinytest.add("minimongo - modify", function (test) {
var modify = function (doc, mod, result) {
Expand Down

0 comments on commit 8e0cf9c

Please sign in to comment.