I'm trying to write a shellsort on Node.js like on the book Algorithms, 4th ed. Sedgewick, Wayne. There all the examples written on Java.
Here is my module:
"use strict";
module.exports = (function() {
function sort(array) {
let size = array.length;
let h = 1;
while(h < size/3) {
h = h * 3 + 1;
}
while(h >= 1) {
for(let i = h; i < size; i++) {
for(let j = i; j >= h && less(array, j, j-h); j = j-h) {
exch(array, j, j-h);
}
}
h = h/3;
}
}
function less(array, i, min) {
return array[i] < array[min];
}
function exch(array, i, min) {
let temp = array[i];
array[i] = array[min];
array[min] = temp;
}
return {
sort: sort
};
})();
I use mocha and chai for testing with this function:
function isSorted(array) {
for(let i = 1, size = array.length; i < size; i++) {
if (array[i] < array[i-1]) {
return false;
}
}
return true;
}
and shell sort not working: mocha test screenshot
Your h may become a floating point number if you use h = h / 3. Try h = Math.floor(h / 3); instead.
Implementation of shell sort algorithm in Javascript
function shellSort(arr){
var len = arr.length;
var gapSize = Math.floor(len/2);
while(gapSize > 0){
for(var i = gapSize; i < len; i++) {
var temp = arr[i];
var j = i;
while(j >= gapSize && arr[j - gapSize] > temp) {
arr[j] = arr[j - gapSize];
j -= gapSize;
}
arr[j] = temp;
}
gapSize = Math.floor(gapSize/2);
}
return arr;
}
function isSorted(array) {
for(let i = 1, size = array.length; i < size; i++) {
if (array[i] < array[i-1]) {
return false;
}
}
return true;
}
var randomArray = [45,86,3,5,97,95,4,24,7,88,93,27,45,90,54,89,74,5,90,73,74,857,834,8394,4231,485,32,54,674,12];
var mySortedArray = shellSort(randomArray);
console.log(mySortedArray);
console.log(isSorted(mySortedArray));
Output:
[3, 4, 5, 5, 7, 12, 24, 27, 32, 45, 45, 54, 54, 73, 74, 74, 86, 88, 89, 90, 90, 93, 95, 97, 485, 674, 834, 857, 4231, 8394]
true
Related
I got a question in exam where I was given an array a
a = [9,8,10,2]
what I need to do is cross iterate the array on itself and get the concatenation of all the possible elements i.e a*a
Once all elements are concatenated in that order, then I need to sum them up. My code is in the snippet:
Also tried in PHP
function sumIt($a) {
$totalSum = 0;
$len1 = count($a);
for($i = 0; $i < $len1; $i++){
for($ii = 0; $ii < $len1; $ii++) {
$totalSum += $a[$i].''.$a[$ii];
}
}
return $totalSum;
}
The input array a can have the following value constraints:
The length of array can be at max 10^5
Value of individual item can be unto 10^6
My code works fine mostly, but on higher end values for array a I start getting time exceed errors which is MAX 4 seconds. I tried with while & foreach loops with no effect. As the code is quite simple, I was wondering if anyone can provide hints on increasing the performance and reducing the execution time.
PS: I tried the --i thing in for loop as well if anyone knows, no difference in that regard as well.
a = [10, 23, 4857, 3, 49, 293, 1, 394,85, 392, 484, 392, 30, 4849,48, 20, 3948, 2493, 84, 3492, 384,92, 384,38, 49, 45, 489, 53,40,9875, 84,9,572,3958, 346,456,45, 56,4564, 6,7867,8, 78,9789, 234,234, 435,34,6, 45,345, 4564,5, 657,45, 45, 345, 667, 5,6756, 877,68, 6765,4, 34, 6, 54, 3, 654, 6, 5, 8776, 43, 32, 67, 89, 876,543,2,34,5, 654, 35, 6, 4, 345, 678, 9, 8, 765, 467,878,9, 4352, 5, 6743, 4, 47, 57,65, 345, 78, 765, 645,63, 56, 5786, 676, 4564,5, 42, 46, 786, 97, 896,567,86, 3777, 65, 6, 877, 65, 67, 2039757584,5348];
function sumIt(a) {
totalSum = 0;
const len1 = a.length;
for(let i = 0; i < len1; i++){
for(let ii = 0; ii < len1; ii++) {
totalSum += +(a[i]+''+a[ii]);
}
}
return totalSum;
}
currentTime = new Date().getTime();
console.log(sumIt(a));
console.log(new Date().getTime() - currentTime);
function sumIt2(a) {
totalSum = 0;
const len1 = a.length;
for(let i = 0; i < len1; i++){
first = Math.pow(10, Math.ceil(Math.log(a[i] + 1)));
for(let j = 0; j < len1; j++) {
totalSum += (first + a[j])
}
}
return totalSum;
}
currentTime = new Date().getTime();
console.log(sumIt2(a));
console.log(new Date().getTime() - currentTime);
The following algorithm (based on #user3386109's idea) is way quicker:
// Generate random array
let a = [];
for (let i = 0; i < 100; i++) {
a.push(Math.floor(Math.random() * 1e6));
}
function sumIt(a) {
totalSum = 0;
const len1 = a.length;
for(let i = 0; i < len1; i++){
for(let ii = 0; ii < len1; ii++) {
totalSum += +(a[i]+''+a[ii]);
}
}
return totalSum;
}
function sumIt2(a) {
let total = 0;
let aLen = a.length;
for (let i = 0; i < aLen; i++) {
for (let j = 0; j < aLen; j++) {
var subtotal = a[i] * Math.pow(10, Math.ceil(Math.log10(a[j] + 1))) + a[j];
total += subtotal;
}
}
return total;
}
function sumIt3(a) {
let subtotal = 0;
let multiplier = 0;
let digitCounts = [a.length, 0, 0, 0, 0, 0, 0];
for (let i = 0; i < a.length; i++) {
subtotal += a[i];
digitCounts[Math.ceil(Math.log10(a[i] + 1))]++;
}
for (let i = 0; i < digitCounts.length; i++) {
multiplier += Math.pow(10, i) * digitCounts[i];
}
return subtotal * multiplier;
}
console.clear();
performance.mark("start");
console.log(sumIt(a));
performance.mark("sumIt");
console.log(sumIt2(a));
performance.mark("sumIt2");
console.log(sumIt3(a));
performance.mark("sumIt3");
performance.measure("sumIt", "start", "sumIt");
performance.measure("sumIt2", "sumIt", "sumIt2");
performance.measure("sumIt3", "sumIt2", "sumIt3");
console.log(performance.getEntriesByType("measure").map(p => p.duration));
However, with larger array sizes (above about 140), the results start to diverge. I think that is more to do with the precision of JS's Number type rather than an underlying problem in the algorithm.
I want to create a program that shows the steps of sorting algorithms, like that:
https://visualgo.net/bn/sorting
https://www.youtube.com/watch?v=kPRA0W1kECg
My problem is that I can't create a interval timer to see the steps of my sorting algorithms
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var array = [10, 150, 17, 200, 300, 110, 400, 260, 105, 157, 180, 208, 400, 122, 40, 266, 123];
drawnLines(array);
function init() {
bubbleSort(array);
ctx.clearRect(0, 0, 800, 500)
drawnLines(array);
}
function drawnLines(array) {
let width;
let position = 5;
for (i = 0; i < array.length; i++) {
width = array[i];
ctx.fillRect(position, 5, 10, width);
ctx.stroke();
position += 20;
}
};
function bubbleSort(array) {
var swapped;
do {
swapped = false;
for (var i = 0; i < array.length - 1; i++) {
setTimeout(function(y) {
if (array[i] > array[i + 1]) {
var temp = array[i];
array[i] = array[i + 1];
array[i + 1] = temp;
swapped = true;
}
console.log(array[i])
}, i * 2000, i)
}
} while (swapped);
};
<script src="https://cdn.jsdelivr.net/npm/sketch-js#1.1.3/js/sketch.min.js"></script>
<canvas id="myCanvas" width="800" height="500"></canvas>
<button type="button" onclick="init()">Bubble Sort</button>
///output:
123
(2) 123
(3) 123
(4) 123
...
(only the last number in my array)
You could use generators with few modifications:
yield in your sorting algo
next() then await sleepSomeTime in init
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var array = [10, 150, 17, 200, 300, 110, 400, 260, 105, 157, 180, 208, 400, 122, 40, 266, 123];
drawnLines(array);
function sleep(ts){
return new Promise((resolve, reject) => {
return setTimeout(resolve, ts)
})
}
async function init() {
const it = bubbleSort(array)
let result = it.next()
while (!result.done) {
ctx.clearRect(0, 0, 800, 500)
drawnLines(array);
result = it.next();
await sleep(100)
}
console.log('finished!')
}
function drawnLines(array) {
let width;
let position = 5;
for (i = 0; i < array.length; i++) {
width = array[i];
ctx.fillRect(position, 5, 10, width);
ctx.stroke();
position += 20;
}
};
function* bubbleSort(array) {
var swapped;
do {
swapped = false;
for (var i = 0; i < array.length - 1; i++) {
if (array[i] > array[i + 1]) {
var temp = array[i];
array[i] = array[i + 1];
array[i + 1] = temp;
swapped = true;
yield
}
}
} while (swapped);
};
<script src="https://cdn.jsdelivr.net/npm/sketch-js#1.1.3/js/sketch.min.js"></script>
<canvas id="myCanvas" width="800" height="500"></canvas>
<button type="button" onclick="init()">Bubble Sort</button>
I used the async generator along with the async processing function. You implement your logic in the processing function while generator does the timing and provides you with array indexes a, b, and Boolean swapped.
var array = [10, 150, 17, 266, 123, 300];
async function* bubbleSortGenerator(array) {
var arr = array.slice(0);
var straight = false;
const end = arr.length - 1;
var iterations = 0;
while (!straight) {
straight = true;
for (var i = 0; i < end - iterations; i++) {
var swapped = false;
if (arr[i] > arr[i + 1]) {
const tmp = arr[i + 1];
arr[i + 1] = arr[i];
arr[i] = tmp;
swapped = true;
straight = false;
}
await new Promise(resolve => setTimeout(resolve, 200)); //here
yield {
a: i,
b: i + 1,
swapped: swapped
};
}
iterations++;
}
yield arr;
}
async function process() {
for await (const val of bubbleSortGenerator(array)) {
console.log(val);
}
}
process();
I wrote code in JavaScript but issues with start value ex: ?-9, ?-87...etc
Input: {88, 105, 3, 2, 200, 0, 10}
<script type="text/javascript">
function RangeValues(){
var a = [88, 105, 3, 2, 200, 0, 10];
var n = a.length;
var pq = [];
for(var i = 0; i<n; i++) {
if(a[i] >= 0 && a[i] <= 99)
pq.push(a[i]);
}
var start = 0;
if(!Array.prototype.last) {
Array.prototype.last = function() {
return this[this.length - 1];
}
}
while(pq.length != 0)
{
var num = pq.last();
pq.pop();
if(num - start > 1){
console.log( (start) +','+ (num-1));
}
if((num - start) == 1)
{
start = num + 1;
console.log(start);
}
}
if(start == 99){
console.log('99');
}
else if(start < 100) {
console.log(start+' to '+99);
}
return 0;
}
RangeValues();
</script>
actual output: 0-9,0-1,0-2,0-87,0-99
Expected: 1,4-9,11-87,89-99
First, you should sort number in array pq descending so the last value is the min number. Try with below solution:
function RangeValues(){
var a = [88, 105, 3, 2, 200, 0, 10];
//var a = [12, 105, 23, 1, 200, 4, 21];
var n = a.length;
var pq = [];
for(var i = 0; i<n; i++) {
if(a[i] >= 0 && a[i] <= 99){
pq.push(a[i]);
}
}
// sort array descending
pq.sort(function(a, b){return b-a});
var start = 0;
if(!Array.prototype.last) {
Array.prototype.last = function() {
return this[this.length - 1];
}
}
while(pq.length != 0){
var num = pq.last();
pq.pop();
if (num-start == 2 || num == 1){
console.log(num-1);
} else if((num - start)>2){
var from = start + 1;
var end = num - 1;
console.log(from+" - "+end);
}
start = num;
}
if (start < 98){
var from = start + 1;
console.log(from+" - "+99);
} else if( start == 98){
console.log(start+1);
}
return 0;
}
RangeValues();
I have array like this
value = [250, 200, 300, 150, 300]
I use this code.
for (var j = 0; j < value.length - 1; j += 1)
{
if (value[j] > value[j + 1])
{
var temp = value[j + 1];
value[j + 1] = value[j];
value[j] = temp;
}
}
But,it's not working. It's results value = [200, 250, 150, 300, 300]
I want to acheive this without using inbuilt function.
use the below code.
var value = [250, 200, 300, 150, 300];
for (var i = 0; i < value.length; i++) {
var swapped = false
for (var j = 0; j < value.length; j++) {
if (value[j] > value[j + 1]) {
temp = value[j + 1];
value[j + 1] = value[j];
value[j] = temp;
swapped = true;
}
}
if (!swapped) {
break;
}
}
console.log(value)
var numbers = [10, 3, 5, 1, 88, 6, 12, 28, 16]
for (var i = 0; i < numbers.length; i++) {
for (var j = 0; j < numbers.length; j++) {
if (numbers[i] < numbers[j]) {
var temp = numbers[j];
numbers[j] = numbers[i];
numbers[i] = temp;
}
}
}
console.log(numbers);
You should have two loops one inside other to sort array
value = [250, 200, 300, 150, 300]
for (var i = 0; i < value.length; i++)
for (var j = i; j < value.length - 1; j++) {
if (value[i] > value[j]) {
var temp = value[j];
value[j] = value[i];
value[i] = temp;
}
}
console.log(value)
I am trying to implement heapsort in Javascript, but there is a undefined element at array.length - 2 and the element at index 0 is unsorted.
Here is the code:
var heapSort = function(array) {
var swap = function(array, firstIndex, secondIndex) {
var temp = array[firstIndex];
array[firstIndex] = array[secondIndex];
array[secondIndex] = temp;
};
var maxHeap = function(array, i) {
var l = 2 * i;
var r = l + 1;
var largest;
if (l <= array.heapSize && array[l] > array[i]) {
largest = l;
} else {
largest = i;
}
if (r <= array.heapSize && array[r] > array[largest]) {
largest = r;
}
if (largest != i) {
swap(array, i, largest);
maxHeap(array, largest);
}
};
var buildHeap = function(array) {
array.heapSize = array.length;
for (var i = Math.floor(array.length / 2); i >= 1; i--) {
maxHeap(array, i);
}
};
buildHeap(array);
for (var i = array.length; i >= 2; i--) {
swap(array, 1, i);
array.heapSize--;
maxHeap(array, 1);
}
};
var a = [55, 67, 10, 34, 25, 523, 1, -2];
heapSort(a);
document.getElementById("getHeapSort").innerHTML = a;
* {
font-family: Arial, sans-serif;
}
<p id="getHeapSort"></p>
I figured that array[i] == undefined when i = array.length. I tried fixing this (setting i = array.length - 1), but the array came out in an entirely different order. I also figured that 0 was never swapped because i is always greater than 0. Again, I tried, and the array came out in a entirely different order.
You were using 1-based indexing instead of 0-based indexing in JavaScript. I also added a trace for your convenience.
Try this:
var heapSort = function(array) {
var swap = function(array, firstIndex, secondIndex) {
var temp = array[firstIndex];
array[firstIndex] = array[secondIndex];
array[secondIndex] = temp;
};
var maxHeap = function(array, i) {
var l = 2 * i;
var r = l + 1;
var largest;
if (l < array.heapSize && array[l] > array[i]) {
largest = l;
} else {
largest = i;
}
if (r < array.heapSize && array[r] > array[largest]) {
largest = r;
}
if (largest != i) {
swap(array, i, largest);
maxHeap(array, largest);
}
};
var buildHeap = function(array) {
array.heapSize = array.length;
for (var i = Math.floor(array.length / 2); i >= 0; i--) {
maxHeap(array, i);
}
};
buildHeap(array);
for (var i = array.length-1; i >= 1; i--) {
swap(array, 0, i);
array.heapSize--;
maxHeap(array, 0);
document.getElementById("getHeapSort").innerHTML = document.getElementById("getHeapSort").innerHTML + a + "<br>";
}
};
var a = [55, 67, 10, 34, 25, 523, 1, -2];
document.getElementById("getHeapSort").innerHTML = a + "<br>";
heapSort(a);
Here is a JFiddle: http://jsfiddle.net/mbL5enL5/1/