using for loop in quick sort in Js - javascript

i am writing quick sort algorthm, and when i testing my code, the result makes me confused.
RangeError: Maximum call stack size exceeded
at Array.push ()
let arr = [0,-1,1,0,1,-1,100,23,17,56,39,47,23,-34,-56];
export default function quickSort(array){
let len = array.length;
if(len <= 1) return array;
let piviot = array.pop();
let left = [], right = [];
for (let i = 0; i < len; i++) {
if(array[i] < piviot){
left.push(array[i]);
}
else{
right.push(array[i])
}
}
return quickSort(left).concat(piviot,quickSort(right));
}
when i change for loop to forEach, problem is disappeared, but i don't know why.
export default function quickSort(array){
let len = array.length;
if(len <= 1) return array;
let piviot = array.pop();
let left = [], right = [];
array.forEach(item => {
if(item < piviot){
left.push(item)
}
else{
right.push(item);
}
});
return quickSort(left).concat(piviot,quickSort(right));
}
Thanks.

This will work as piviot = array.pop(); changes array size which causes the issue
export default function quickSort(array){
let len = array.length;
if(len <= 1) return array;
let piviot = array.pop();
len = array.length;
let left = [], right = [];
for (let i = 0; i < len; i++) {
if(array[i] < piviot){
left.push(array[i]);
}
else{
right.push(array[i])
}
}
return quickSort(left).concat(piviot,quickSort(right));
}

I won't write the quicksort algorithm for you, but I will explain the behavior:
Why the first piece of code overflows stack
This is very common in recursive functions that never end. You are never reaching the magic
if(len <= 1) return array;
All your function calls end up on the call stack. There is a limit depending on the browser on how many can be called on the stack at the same time. Thus when you reach that limit with recursion (and not only) you overflow the stack.
Why for each works
It doesn't, it just won't overflow your stack. Why? Foreach is a callback. It won't run first and then go to the next line.
Using foreach, you are effectively calling the next recursion with empty arrays and they return automatically.

Related

Is there any leak in my code, Only 1 case isn't working I don't know why?

I am trying to write a programme to move all the zeroes at the end of the array and retain and the original order of other elements.
Here is my code:-
var moveZeros = function (arr) {
// TODO: Program me
var k=0;
for (var i=0;i<=arr.length-1;i++){
var s=arr[i];
if (s===0){
arr.splice(i,1);
k++
}
}
for (var j=0;j<=k-1;j++){
arr.push(0);
}
return arr
}
But when zeros are next to each other like [1,0,0,1] it doesn't work.
I don't see why.
Can anybody tell?
And please also explain why k-1 not k I wrote k-1 by observing the output.
Please don't tell the answer to the original problem I just want to fix the problem with my code. :)
The problem is that in each loop you increase the i variable by one. Meaning, you go to the next index. But if you have 2 or more zeros in the row, and you remove the first one, you shouldn't change i to i + 1, because i already points at a new value in the array(which is zero) :)
var moveZeros = function (arr) {
// TODO: Program me
var k = 0;
for (var i = 0; i <= arr.length - 1;) {
var s = arr[i];
if (s === 0) {
arr.splice(i, 1);
k++;
} else {
i++;
}
}
for (var j = 0; j <= k - 1; j++) {
arr.push(0);
}
return arr;
};
console.log(moveZeros([1,0,0,2]));

How to store the numbers for the 2048 game

I have been trying to implement the game 2048.
I can add numbers in random positions of the grid and I can also slide them to a side, as that is what the console.log shows me.
But somehow I am not able to maintain that effect of a slide. Whenever I call key again, the rows are like there was no effect of the previous slides.
function slide(row) {
arr = row.filter(e => e);
let missing = 4 - arr.length;
let zeros = Array(missing).fill(0);
arr = arr.concat(zeros);
console.log(arr);
return arr;
}
function key() {
for (let i = 0; i < 4; i++) {
slide(grid[i]);
}
addNumber();
}
The problem is that you do not modify the row that the function receives as argument. Instead you create a new array, which you return. But then the caller does not process the return value.
Instead of:
for (let i = 0; i < 4; i++) {
slide(grid[i])
}
do:
for (let i = 0; i < 4; i++) {
grid[i] = slide(grid[i])
}
Now your grid will actually stay in sync with what the slide function does.

Slow down for-loop inside while-loop (Javascript)

So I'm trying to visualize a sorting algorithm in Vanilla JS and for this I need the actual sorting function to not sort it all in the fraction of a second but to wait e.g. 250ms after each iteration.
This is the Bubble Sort code (which does work):
function sortArray(){
let arr = inputArray; //arr is the array to get sorted.
let l = arr.length;
let swapped;
//---Bubble sort---
do {
swapped = false;
for (let i = 0; i < l-1; i++) {
if (arr[i] > arr[i+1]){
let temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
swapped = true;
}
}
}while (swapped);
//---Bubble sort---
display.innerText = JSON.stringify(arr); //Display the sorted Array to the user
}
Now I researched on how to slow down a loop in JS and tried a couple of different ways.
For example:
function sortArray(){
let arr = inputArray; //arr is the array to get sorted.
let l = arr.length;
let swapped;
//---Bubble sort---
do {
swapped = false;
for (let i = 0; i < l-1; i++) {
setTimeout(() =>{
if (arr[i] > arr[i+1]){
let temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
swapped = true;
n++;
}
arrayDisplay.innerText =JSON.stringify(arr);
},250 *i);
}
}while (swapped);
//---Bubble sort---
display.innerText = JSON.stringify(arr); //Display the sorted Array to the user
}
Here I tried to use the setTimeout function inside the for-loop which does theoretically work but it does only slow down and display each step for the for-loop but stops after each run instead of looping again (while(swapped))(obviously, but I don't know how to fix it). For each while loop I to press the button again.
I also tried wrapping the whole do-while construction inside the setTimeout and add an additional set Timeout inside the for-loop. That simply crashed my browser. I also tried a couple of other constellations but those also either crashed the browser or didn't sort at all.
setTimeout() creates an asynchronous process but for and while loops normally runs synchronously, so it doesn't work to do it like that. If your environment supports async-await syntax, you can use that to make for and while run asynchronously.
Annotate the function as async, promisify the timeout and then await it, like this:
async function sortArray(){
let arr = inputArray; //arr is the array to get sorted.
let l = arr.length;
let swapped;
//---Bubble sort---
do {
swapped = false;
for (let i = 0; i < l-1; i++) {
await new Promise(resolve => setTimeout(() =>{
if (arr[i] > arr[i+1]){
let temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
swapped = true;
n++;
}
arrayDisplay.innerText =JSON.stringify(arr);
resolve();
}, 250));
}
}while (swapped);
//---Bubble sort---
display.innerText = JSON.stringify(arr); //Display the sorted Array to the user
}
If your environment doesn't support async-await, you're going to need to use a more complex approach with callback functions instead of for and while loops.
Keep in mind that an async function will always return a Promise. It's not relevant in this case since your function creates side-effects and doesn't return anything.

how to compare the running time between different functions

First, I want to thanks to Bails for his answer on question console.time shows different time running the same function. But it still confusing me that how can I compare running time of two different functions
Here's the code I have tried.
function fun1(arr) {
let a = 0
for(let i = 0;i < arr.length; i++) {
a += arr[i]
}
return a
}
function fun2(arr) {
let a = 0
arr.forEach((v) => {
a += v
})
return a
}
let array = []
for(let i = 0;i < 100; i++) {
array.push(Math.random())
}
console.time('fun1')
fun1(array)
console.timeEnd('fun1')
console.time('fun2')
fun2(array)
console.timeEnd('fun2')
We all know that forEach is faster than for. But when I run the code above, I got different results:

Why this reverse function isn't working?

Why isn't this working?
ps. I don't want to use any other variable to make it work, and i don't want to use built in functions, just asking why THIS is not working?
function reverse(arr){
for(var i =0; i< arr.length; i++){
arr.push(arr[arr.length-i]);
}
return arr;
}
There are a lot of flaws in your code.
When you start pushing arr.push(arr[arr.length-i]); the array length increases, thereby, you won't get a consistency in the data.
This goes inside an infinite loop, as every time, the arr is ahead of its length.
It is better to use another variable and reverse, or you can use the built-in reverse() function. There's nothing wrong in having another variable and add temporary contents in it.
Solutions:
Using a temporary array:
function reverse(arr) {
var final = [];
for (var i = arr.length - 1; i >= 0; i--) {
final.push(arr[i]);
}
return final;
}
Using built-in function (Array.prototype.reverse()):
function reverse(arr) {
return arr.reverse();
}
Using few temporary variables:
a = [5,4,3,2,1];
function reverse(arr) {
var i = 0, j = arr.length - 1;
for (i = 0; i < j; i++, j--) {
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
return arr;
}
console.log(reverse(a));
You're going to run out of memory. What you're doing is adding what was initially the last element of that array infinitely to the end of your array. Every time that you call arr.push(...) you increase arr.length by one. Your for loop will never be able to finish because i will never be less than arr.length
I don't want to use any other variable to make it work, and i don't want to use built in functions
You cannot.
Use temporary array for result
function reverse(arr) {
var res = []
for (var i = arr.length - 1; i > -1; i--) {
res.push(arr[i]);
}
return res;
}

Categories

Resources