it's a simple code, but returns different results in Andriod and Iphone.
var str = [1,2,3,4,5].sort(function () {
return -1;
})
document.write(str);
In MDN(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) it says
If compareFunction(a, b) is less than 0, sort a to a lower index than b, i.e. a comes first.
If compareFunction(a, b) returns 0, leave a and b unchanged with respect to each other, but sorted with respect to all different elements. Note: the ECMAscript standard does not guarantee this behaviour, and thus not all browsers (e.g. Mozilla versions dating back to at least 2003) respect this.
If compareFunction(a, b) is greater than 0, sort b to a lower index than a.
compareFunction(a, b) must always return the same value when given a specific pair of elements a and b as its two arguments. If inconsistent results are returned then the sort order is undefined.
So the result should be 1,2,3,4,5.
But is Iphone it shows 5,4,3,2,1
Here is a link for you to try this code. http://www.madcoder.cn/demos/ios-test.html
And after I did more and more test. I found Iphone is doing a different sorting.
Here is a link shows how sort works: http://www.madcoder.cn/demos/ios-test2.html
The javascript engines use different algorithms for their sort function. Since the compare function doesn't compare values, you get the result of the inner workings of the different algorithms instead of having a sorted result.
Looking at the source code of V8 engine (Chrome) and JavaScriptCore (which seems to be used by Safari, or at least the sort function gives the same result, so I guess it uses the same kind of algorithm), you can view the functions that are being used.
Not that it might not be exactly the functions used, what's important is that the algorithms are different. They give the same result if you actually compare values, but if not, the result is dependent on the way they operate, not on the function itself. At least not completely.
Here's V8 engine sorting function. You'll see that for arrays bigger than 10 elements, the algorithm isn't the same, so the result for arrays smaller than 10 elements is different than for those bigger than 10 elements.
You can find following algorithms here: https://code.google.com/p/chromium/codesearch#chromium/src/v8/src/js/array.js&q=array&sq=package:chromium&dr=C
comparefn = function(a, b) {
return -1
}
var InsertionSort = function InsertionSort(a, from, to) {
for (var i = from + 1; i < to; i++) {
var element = a[i];
for (var j = i - 1; j >= from; j--) {
var tmp = a[j];
var order = comparefn(tmp, element);
if (order > 0) {
a[j + 1] = tmp;
} else {
break;
}
}
a[j + 1] = element;
}
console.log(a);
}
var GetThirdIndex = function(a, from, to) {
var t_array = new InternalArray();
// Use both 'from' and 'to' to determine the pivot candidates.
var increment = 200 + ((to - from) & 15);
var j = 0;
from += 1;
to -= 1;
for (var i = from; i < to; i += increment) {
t_array[j] = [i, a[i]];
j++;
}
t_array.sort(function(a, b) {
return comparefn(a[1], b[1]);
});
var third_index = t_array[t_array.length >> 1][0];
return third_index;
}
var QuickSort = function QuickSort(a, from, to) {
var third_index = 0;
while (true) {
// Insertion sort is faster for short arrays.
if (to - from <= 10) {
InsertionSort(a, from, to);
return;
}
if (to - from > 1000) {
third_index = GetThirdIndex(a, from, to);
} else {
third_index = from + ((to - from) >> 1);
}
// Find a pivot as the median of first, last and middle element.
var v0 = a[from];
var v1 = a[to - 1];
var v2 = a[third_index];
var c01 = comparefn(v0, v1);
if (c01 > 0) {
// v1 < v0, so swap them.
var tmp = v0;
v0 = v1;
v1 = tmp;
} // v0 <= v1.
var c02 = comparefn(v0, v2);
if (c02 >= 0) {
// v2 <= v0 <= v1.
var tmp = v0;
v0 = v2;
v2 = v1;
v1 = tmp;
} else {
// v0 <= v1 && v0 < v2
var c12 = comparefn(v1, v2);
if (c12 > 0) {
// v0 <= v2 < v1
var tmp = v1;
v1 = v2;
v2 = tmp;
}
}
// v0 <= v1 <= v2
a[from] = v0;
a[to - 1] = v2;
var pivot = v1;
var low_end = from + 1; // Upper bound of elements lower than pivot.
var high_start = to - 1; // Lower bound of elements greater than pivot.
a[third_index] = a[low_end];
a[low_end] = pivot;
// From low_end to i are elements equal to pivot.
// From i to high_start are elements that haven't been compared yet.
partition: for (var i = low_end + 1; i < high_start; i++) {
var element = a[i];
var order = comparefn(element, pivot);
if (order < 0) {
a[i] = a[low_end];
a[low_end] = element;
low_end++;
} else if (order > 0) {
do {
high_start--;
if (high_start == i) break partition;
var top_elem = a[high_start];
order = comparefn(top_elem, pivot);
} while (order > 0);
a[i] = a[high_start];
a[high_start] = element;
if (order < 0) {
element = a[i];
a[i] = a[low_end];
a[low_end] = element;
low_end++;
}
}
}
if (to - high_start < low_end - from) {
QuickSort(a, high_start, to);
to = low_end;
} else {
QuickSort(a, from, low_end);
from = high_start;
}
}
};
InsertionSort([1, 2, 3, 4, 5], 0, 5);
//QuickSort is recursive and calls Insertion sort, so you'll have multiple logs for this one
QuickSort([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], 0, 13);
//You'll see that for arrays bigger than 10, QuickSort is called.
var srt = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13].sort(function() {
return -1
})
console.log(srt)
And JavaScriptCore uses merge sort. You can find this algorithm here:
http://trac.webkit.org/browser/trunk/Source/JavaScriptCore/builtins/ArrayPrototype.js
function min(a, b) {
return a < b ? a : b;
}
function merge(dst, src, srcIndex, srcEnd, width, comparator) {
var left = srcIndex;
var leftEnd = min(left + width, srcEnd);
var right = leftEnd;
var rightEnd = min(right + width, srcEnd);
for (var dstIndex = left; dstIndex < rightEnd; ++dstIndex) {
if (right < rightEnd) {
if (left >= leftEnd || comparator(src[right], src[left]) < 0) {
dst[dstIndex] = src[right++];
continue;
}
}
dst[dstIndex] = src[left++];
}
}
function mergeSort(array, valueCount, comparator) {
var buffer = [];
buffer.length = valueCount;
var dst = buffer;
var src = array;
for (var width = 1; width < valueCount; width *= 2) {
for (var srcIndex = 0; srcIndex < valueCount; srcIndex += 2 * width)
merge(dst, src, srcIndex, valueCount, width, comparator);
var tmp = src;
src = dst;
dst = tmp;
}
if (src != array) {
for (var i = 0; i < valueCount; i++)
array[i] = src[i];
}
return array;
}
console.log(mergeSort([1, 2, 3, 4, 5], 5, function() {
return -1;
}))
Again these may not be exactly the functions used in each browser, but it shows you how different algorithms will behave if you don't actually compare values.
Related
Please find my quicksort implementation below in javascript.
const A = [4, 6, 2, 5, 7, 9, 1, 3];
const partition = function(l, h) {
let pivot = A[l];
let i = l;
let j = h;
while(A[i] <= pivot) {
i++;
}
while(A[j] > pivot) {
j--;
}
if (i < j) {
let temp = A[i];
A[i] = A[j];
A[j] = temp;
}
let temp1 = A[l];
A[l] = A[j];
A[j] = temp1;
return j;
}
const quickSort = function (l, h) {
if (l < h) {
let piIdx = partition(l, h);
console.log('the pidx is ', piIdx);
quickSort(l, piIdx - 1);
quickSort(piIdx + 1, h);
}
}
quickSort(0, A.length - 1);
console.log('array after quicksort call ', A);
The output is as below:
[ 1, 2, 3, 5, 7, 9, 6, 4 ]
The last set of elements haven't been sorted properly. Could anyone please have a look and let me know the problem.
thanks
The problem is that your partition function will at most perform 2 swaps. This cannot be right.
The process of swapping (the first one in your code) should be repeated until i has arrived at j.
Not the problem, but as the function is mutating A, that should be a parameter of the function -- that is best practice.
Here is an update of your function, with a test script below it that tests the implementation for 1000 arrays that are randomly shuffled:
const partition = function(A, l, h) { // A is parameter
let pivot = A[l];
let i = l;
let j = h;
while (true) { // Keep going
while(A[i] <= pivot) {
i++;
}
while(A[j] > pivot) {
j--;
}
if (i >= j) break; // All done
let temp = A[i];
A[i] = A[j];
A[j] = temp;
}
A[l] = A[j];
A[j] = pivot; // We already know A[l], no need for temp
return j;
}
const quickSort = function (A, l, h) { // A is parameter
if (l < h) {
let piIdx = partition(A, l, h);
quickSort(A, l, piIdx - 1);
quickSort(A, piIdx + 1, h);
}
}
// Test the implementation
function shuffle(a) {
let i = a.length;
while (i) {
let j = Math.floor(Math.random() * i--);
[a[i], a[j]] = [a[j], a[i]];
}
}
const A = [...Array(50).keys()]; // is sorted
const ref = A.toString(); // string to compare solution with
for (let attempt = 0; attempt < 1000; attempt++) {
shuffle(A);
quickSort(A, 0, A.length - 1);
if (A.toString() != ref) {
console.log('Error: array not sorted after quicksort call ', ...A);
break;
}
}
console.log("all tests done");
You are halfway there ,
you are iterating the low and high but those both along with there swap needs to be in a loop that goes from low all the way to high
meaning until high does not overlap low , the loop will keep on going .
and once the loop breaks you got your index of putting the pivot
you also need to have a pivot index that will help you at the end to swap the j with the pivot index;
so it should be like this
var pivotIndex=l;
while(i<j){
while(A[i] <= pivot) {
i++;
}
while(A[j] > pivot) {
j--;
}
if (i < j) {
let temp = A[i];
A[i] = A[j];
A[j] = temp;
}
let temp1 = A[l];
A[l] = A[j];
A[j] = temp1;
}
[nums[pivotIndex],nums[j]]=[nums[j],[nums[pivotIndex]]
return j;}
I hope this help
I am doing Integer right triangles. I have written a very simple brute force solution that runs through every combination.
I am pretty sure that there would be a better method for working out the answer but I can't think of any that reduce the computational complexity. Here's my current solution:
const main = () => {
let map = new Map();
for (let a = 1; a < 1001; a++) {
for (let b = a; b < 1001; b++) {
const c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
const perimeter = (a + b + c);
if (perimeter > 1000) {
break;
}
if (c % 1 === 0) {
map.set(perimeter, (map.get(perimeter) ? map.get(perimeter) + 1 : 1));
}
}
}
// Sorting by the incremented value then returning the highest
return new Map([...map.entries()].sort((a, b) => b[1] - a[1]))
.entries()
.next()
.value[0];
};
console.log(main());
Thanks!
Some remarks about your code:
As the perimeter cannot be larger than 1000, and a < b < c, a should not have to iterate up to 1000, but only to 332. Similarly, b should not iterate further than 1000 - 2*a.
You can avoid taking the square root by increasing the previous value for c with 1, and adjusting the corresponding square. Similarly you can apply incremental logic to the squares of a and b, and the sum of squares.
Sorting is overkill. You only need to find the entry with the maximum count. So just iterate over the map to find that maximum
Before showing a faster method, the above will already speed up your code considerably. Your code would then look like this:
const main = () => {
let map = new Map();
for (let a = 1; a < 333; a++) {
let limit = 1000 - 2*a;
let aSquare = Math.pow(a, 2);
let aSquarePlusBSquare = 2*aSquare;
let c = Math.floor(a * 1.14142);
let cSquare = c*c;
let perimeter = 2*a+c;
for (let b = a+1; b < limit; b++) {
aSquarePlusBSquare += 2*b - 1;
perimeter++;
while (cSquare < aSquarePlusBSquare) {
c++;
perimeter++;
cSquare += 2*c - 1;
}
if (perimeter > 1000) {
break;
}
if (cSquare === aSquarePlusBSquare) {
map.set(perimeter, (map.get(perimeter) ? map.get(perimeter) + 1 : 1));
}
}
}
let max = 0;
for (let [i, k] of map) {
if (k <= max) continue;
max = k;
result = i;
}
return result;
};
console.log(main());
Now, you can also go for a different algorithm. I implemented one that uses the tree of primitive Pythagorian triplets. This performs 20 times better than your original code, and like 5 times better than the above implementation:
function main() {
let map = new Map;
function recur(a, b, c) {
let sum = a+b+c;
if (sum >= 1001) return;
// As this is a primitive case, also count the multiples:
for (let p = sum; p < 1001; p += sum) map.set(p, map.get(p)+1 || 1);
// Calculate the 3 "children" of this primitive Pythagorean triple,
// using Berggren's tree
let a2 = a<<1, a4 = a<<2, b2 = b<<1, b4 = b<<2;
let temp = a2 - b2 + (c<<1);
a = temp - a;
b += temp;
c += temp;
recur(a, b, c);
a += b4;
b += b2;
c += b4;
recur(a, b, c);
recur(a-a2, b-a4, c-a4);
}
recur(3, 4, 5);
let max = 0;
for (let [i, k] of map) {
if (k <= max) continue;
max = k;
result = i;
}
return result;
}
console.log(main());
I have the following code:
let arr = [];
for (i = 14; i <= 31; i++) {
let d = "2018-08-" + String(i);
arr.push({
date: d
});
}
arr.sort((a, b) => a.date - b.date);
console.log(arr);
I know sort() is supposed to be used only with numbers
I know that comparing strings with - is a bad idea
I already localized and fixed the original bug in my code, but...
There is something that fascinates me about this buggy code: the result.
Subtracting a string from another string gives NaN, so I'd expect the array to stay the same (14, 15, 16, 17... 31), or maybe to get completely flipped (31, 30, 29, 28... 14).
Instead, the actual (consistent) result is
I'm very curious about knowing why exactly sort() is outputting that sequence of strings. Why 31, 15 and 23 get moved, and why do they get moved to those particular positions?
This behavior is probably easier to understand with a simpler array.
For example:
let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
arr.sort(() => NaN)
console.log(arr)
In chrome this returns an array order like: [0,11,2,3,4,5,1,7,8,9,10,6].
This is peculiar, but if you look at the implementation of sorting in the V8 code you will find a mix of quicksort and insertion sort. In fact if will recursively call quicksort until the arrays being recursed on have a length less than 10, then it will switch to insertions sort.
The way quick sort chooses the pivot explains the behavior you're seeing. Here's a snippet with the slightly truncated code from V8:
arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
function comparefn(a,b){
return NaN
}
function InsertionSort(a, from, to) {
for (var i = from + 1; i < to; i++) {
var element = a[i];
for (var j = i - 1; j >= from; j--) {
var tmp = a[j];
var order = comparefn(tmp, element);
if (order > 0) {
a[j + 1] = tmp;
} else {
break;
}
}
a[j + 1] = element;
}
};
function QuickSort(a, from, to) {
var third_index = 0;
while (true) {
// Insertion sort is faster for short arrays.
if (to - from <= 10) {
InsertionSort(a, from, to);
return;
}
third_index = from + ((to - from) >> 1);
// Find a pivot as the median of first, last and middle element.
var v0 = a[from];
var v1 = a[to - 1];
var v2 = a[third_index];
var c01 = comparefn(v0, v1);
if (c01 > 0) {
// v1 < v0, so swap them.
var tmp = v0;
v0 = v1;
v1 = tmp;
} // v0 <= v1.
var c02 = comparefn(v0, v2);
if (c02 >= 0) {
// v2 <= v0 <= v1.
var tmp = v0;
v0 = v2;
v2 = v1;
v1 = tmp;
} else {
// v0 <= v1 && v0 < v2
var c12 = comparefn(v1, v2);
if (c12 > 0) {
// v0 <= v2 < v1
var tmp = v1;
v1 = v2;
v2 = tmp;
}
}
// v0 <= v1 <= v2
a[from] = v0;
a[to - 1] = v2;
var pivot = v1;
var low_end = from + 1; // Upper bound of elements lower than pivot.
var high_start = to - 1; // Lower bound of elements greater than pivot.
a[third_index] = a[low_end];
a[low_end] = pivot;
// From low_end to i are elements equal to pivot.
// From i to high_start are elements that haven't been compared yet.
partition: for (var i = low_end + 1; i < high_start; i++) {
var element = a[i];
var order = comparefn(element, pivot);
if (order < 0) {
a[i] = a[low_end];
a[low_end] = element;
low_end++;
} else if (order > 0) {
do {
high_start--;
if (high_start == i) break partition;
var top_elem = a[high_start];
order = comparefn(top_elem, pivot);
} while (order > 0);
a[i] = a[high_start];
a[high_start] = element;
if (order < 0) {
element = a[i];
a[i] = a[low_end];
a[low_end] = element;
low_end++;
}
}
}
if (to - high_start < low_end - from) {
QuickSort(a, high_start, to);
to = low_end;
} else {
QuickSort(a, from, low_end);
from = high_start;
}
}
};
// run it
QuickSort(arr, 0, arr.length)
console.log(arr)
If you look at this, especially the way the pivot is chosen and when it switches to insertion sort, you will see why the results are ordered the way they are.
When the compare function always returns NaN, all the ifs in the code are bypassed that look like this:
var c12 = comparefn(v1, v2);
if (c12 > 0) { /* etc /*}
Meaning the whole sort reduces to the smaller:
arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
function comparefn(a,b){
//console.log(a, b)
return NaN
}
function QuickSort(a, from, to) {
var third_index = 0;
while (true) {
// Insertion sort is faster for short arrays.
if (to - from <= 10) {
return;
}
third_index = from + ((to - from) >> 1);
// Find a pivot as the median of first, last and middle element.
var v0 = a[from];
var v1 = a[to - 1];
var v2 = a[third_index];
a[from] = v0;
a[to - 1] = v2;
var pivot = v1;
var low_end = from + 1; // Upper bound of elements lower than pivot.
var high_start = to - 1; // Lower bound of elements greater than pivot.
a[third_index] = a[low_end];
a[low_end] = pivot;
partition: for (var i = low_end + 1; i < high_start; i++) {
var element = a[i];
}
if (to - high_start < low_end - from) {
QuickSort(a, high_start, to);
to = low_end;
} else {
QuickSort(a, from, low_end);
from = high_start;
}
}
};
QuickSort(arr, 0, arr.length)
console.log(arr)
So I'm working on Khan Academy's Algorithms course, and am trying to implement a recursive merge sort in Javascript. Here is my code so far:
var mergeSort = function(array, p, r) {
if(r>p) {
var q = floor(r/2);
mergeSort(array, p, q);
mergeSort(array, q+1, r);
merge(array, p, q, r);
}
};
merge is a function provided by Khan Academy to merge the subarrays back together. It is giving me the error: 'Uncaught RangeError: Maximum call stack size exceeded'.
EDIT: More details: I am fairly sure the error is in my code, there code is purposefully obfuscated and unreadable because the user needs to implement it themselves in a later challenge.
Here is the code that actually calls the mergeSort function initially and declares the array:
var array = [14, 7, 3, 12, 9, 11, 6, 2];
mergeSort(array, 0, array.length-1);
println("Array after sorting: " + array);
Program.assertEqual(array, [2, 3, 6, 7, 9, 11, 12, 14]);
And here is the code for the merge function, although it is obfuscared as I mentioned above:
var merge = function(array, p, q, r) {
var a = [],
b = [],
c = p,
d, e;
for (d = 0; c <= q; d++, c++) {
a[d] = array[c];
}
for (e = 0; c <= r; e++, c++) {
b[e] = array[c];
}
c = p;
for (e = d = 0; d < a.length && e < b.length;) {
if (a[d] < b[e]) {
array[c] = a[d];
d++;
} else {
array[c] = b[e];
e++;
}
c++;
}
for (; d < a.length;) {
array[c] = a[d];
d++;
c++;
}
for (; e < b.length;) {
array[c] = b[e];
e++;
c++;
}
};
They also require my code inside of the mergeSort function be of the form:
if (____) {
var ____ = ____;
mergeSort(____,____,____);
mergeSort(____,____,____);
merge(____,____,____,____);
}
Mergesort is a divide and conquer algorithm which splits the range of indices to sort in two, sorts them separately, and then merges the results.
Therefore, middle variable should be the arithmetic mean of from and to, not the half of to.
I have renamed the variables to make it more understandable:
var mergeSort = function(array, from, to) {
if(to > from) {
var middle = Math.floor( (from+to)/2 ); // Arithmetic mean
mergeSort(array, from, middle);
mergeSort(array, middle+1, to);
merge(array, from, middle, to);
}
};
q is supposed to be the half way point between p and r, but you've failed to take into account that the starting point (i.e. p) might not be 0 when you do this:
var q = floor(r/2);
You need to do something like:
var q = floor((r-p)/2) + p;
Although as #Oriol points out the middle point is actually exactly the same as the arithmetic mean and so the calculation can be simplified.
Just for the sake of implementation of the merge sort in JS
function merge(arr){
if(arr.length <= 1) return arr;
let mid = Math.floor(arr.length/2);
let left = merge( arr.slice(0, mid));
let right = merge(arr.slice(mid))
function mergeSort(arr1, arr2) {
let result = [];
let i=0;
let j=0;
while(i< arr1.length && j < arr2.length) {
if(arr1[i] < arr2[j]){
result.push(arr1[i])
i++;
} else {
result.push(arr2[j])
j++;
}
}
while(i < arr1.length) {
result.push(arr1[i])
i++;
}
while(j < arr2.length){
result.push(arr2[j])
j++;
}
return result
}
return mergeSort(left,right)
}
console.log(merge([1,4,3,6,2,11,100,44]))
High level strategy
the merge sort works on the principle that it's better to sort two numbers than to sort a large list of numbers. So what it does is that it breaks down two lists into their individual numbers then compares them one to the other then building the list back up. Given a list of say 1,3,2, it'll split the list into 1 and 3,2 then compare 3 to 2 to get 2,3 and then compare the list of 2,3 to 1. If 1 is less than the first element in list of 2,3 it simply places 1 in front of the list. Just like that, the list of 1,3,2 is sorted into 1,2,3.
pseudocode-steps
1.take first member of first array
2.compare to first member of second array
3.if first member of first array is less than first member
of second array
4.put first member into sorted array
5.now merge first array minus first element
with second array
6.else take first member of second array
merge first array with remaining portion of second array
7.return sorted array
function mergesorted(list1, list2) {
let sorted = [];
if (list1.length === 0 || list2.length === 0) {
return list1.length === 0 ? list2.length === 0 ? [] : list2 : list1;
}
if (list1[0] < list2[0]) {
sorted.push(list1[0])
return sorted.concat(mergesorted(list1.slice(1), list2))
} else {
sorted.push(list2[0])
return sorted.concat(mergesorted(list1, list2.slice(1)))
}
}
console.log(mergesorted([1, 2], [3, 4])) //should: [1,2,3,4]
console.log(mergesorted([1,2], [3])) //should: [1,2,3]
Merge sort implementation, stable and in place
function sort(arr, start, end) {
if (start >= end-1) return;
var mid = start + ~~((end-start)/2);
// after calling this
// left half and right half are both sorted
sort(arr, start, mid);
sort(arr, mid, end);
/**
* Now we can do the merging
*/
// holding merged array
// size = end-start
// everything here will be copied back to original array
var cache = Array(end-start).fill(0);
var k=mid;
// this is O(n) to arr[start:end]
for (var i=start, r=0;i<mid;r++,i++) {
while (k<end && arr[k] < arr[i]) cache[r++] = arr[k++];
cache[r] = arr[i];
}
// k marks the position of the element in the right half that is bigger than all elements in the left
// effectively it tells that we should only copy start~start+k element from cache to nums
// because the rests are the same
for (var i=0;i<k-start;i++) arr[i+start]=cache[i];
}
A nice solution:
const merge = (left, right) => {
const resArr = [];
let leftIdx = 0;
let rightIdx = 0;
while (leftIdx < left.length && rightIdx < right.length) {
left[leftIdx] < right[rightIdx]
? resArr.push(left[leftIdx++])
: resArr.push(right[rightIdx++]);
}
return [...resArr, ...left.slice(leftIdx), ...right.slice(rightIdx)];
};
const mergeSort = arr =>
arr.length <= 1
? arr
: merge(
mergeSort(arr.slice(0, Math.floor(arr.length / 2))),
mergeSort(arr.slice(Math.floor(arr.length / 2)))
);
try this
const mergeTwoSortedArr = (arr1 = [], arr2 = []) => {
let i = 0,
j = 0,
sortedArr = [];
while(i < arr1.length || j < arr2.length) {
if(arr1[i] <= arr2[j] || (i < arr1.length && j >= arr2.length)) {
sortedArr.push(arr1[i]);
i++;
}
if(arr2[j] <= arr1[i] || (j < arr2.length && i >= arr1.length)) {
sortedArr.push(arr2[j]);
j++;
}
}
return sortedArr;
}
const mergeSort = (arr) => {
if(arr.length === 0 || arr.length === 1) {
return arr;
}
var mid = Math.floor(arr.length / 2);
var left = mergeSort(arr.slice(0, mid));
var right = mergeSort(arr.slice(mid));
return mergeTwoSortedArr(left, right);
}
when trying this
mergeSort([5, 2, 1, 4]) //[1, 2, 4, 5]
Time Complexity O(nlogn)
logn --> decomposition
n comaprison
Time complexity O(nlogn)
In prototype the cumbersome for:
for (i=0; i<10; i++) { ... }
can be written as
$R(0, 10).each(function(i){ ... });
Is there an equivalent of range in JQuery ?
See http://code.google.com/p/jquery-utils/source/browse/trunk/src/jquery.arrayUtils.js?r=452
jQuery does not provide range expansion natively, but it's an easy addition. There are only two parts to it. First the range function should return an array with the each item in the range expanded to an array value. Next add a method to Array to iterate each object passing in a handler function.
Here we define forEach that's part of the ECMA-262 standard for iterating over arrays. See MDC for more details.
if (!Array.prototype.forEach) {
Array.prototype.forEach = function(fun /*, thisp*/) {
var len = this.length >>> 0;
if (typeof fun != "function")
throw new TypeError();
var thisp = arguments[1];
for (var i = 0; i < len; i++) {
if (i in this)
fun.call(thisp, this[i], i, this);
}
};
}
Next, we need a function to expand ranges to an array within the jQuery namespace. Taken from the above URL (original source - http://blog.outofhanwell.com/2006/03/29/javascript-range-function/)
:
$.extend({
// Returns a range object
// Author: Matthias Miller
// Site: http://blog.outofhanwell.com/2006/03/29/javascript-range-function/
range: function() {
if (!arguments.length) { return []; }
var min, max, step;
if (arguments.length == 1) {
min = 0;
max = arguments[0]-1;
step = 1;
}
else {
// default step to 1 if it's zero or undefined
min = arguments[0];
max = arguments[1]-1;
step = arguments[2] || 1;
}
// convert negative steps to positive and reverse min/max
if (step < 0 && min >= max) {
step *= -1;
var tmp = min;
min = max;
max = tmp;
min += ((max-min) % step);
}
var a = [];
for (var i = min; i <= max; i += step) { a.push(i); }
return a;
}
});
Alrighty, now we can do:
$.range(2, 10).forEach(function(v) {
console.log(v); // 2, 3, 4, .., 9
});
Or use it with a custom step value instead of 1
$.range(2, 20, 4).forEach(function(v) {
console.log(v); // 2, 6, 10, 14, 18
});
I'd prefer a generator to an array - more elegant (imho) and more memory efficient.
function Range(low, high){
this.low = low;
this.high = high;
}
Range.prototype.__iterator__ = function(){
for (var i = this.low; i <= this.high; i++)
yield i;
};
Then you can simply
var range = new Range(3, 5);
for (var i in range)
print(i); // prints 3, then 4, then 5 in sequence
From: https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Iterators_and_Generators