Implementing Insert Function - javascript

I am currently working through Khan Academy's algorithm course, which uses JS to teach fundamental algorithms. I am currently in the process of implementing an insertion sort, but have found a problem.
We are writing a function which takes in an array, index to start from and value, in order to insert a number in the correct ordered position. I have written said function here:
var insert = function(array, rightIndex, value) {
for (var i = rightIndex; array[i] >= value; i--) {
array[i+1]=array[i];
array[i] = value;
}
return array;
};
This works fine, and performs as it should, however it does not pass KA's automated marking system. They give guidelines for the code and suggest it be done as such:
for(var ____ = _____; ____ >= ____; ____) {
array[____+1] = ____;
}
____;
Does anyone know how I could reiterate my code to conform to these standards?

I had a similar solution as you and didn't pass their automated test. If you look later at "Challenge: Implement insertion sort" they actually go ahead and implement the function for you:
var insert = function(array, rightIndex, value) {
for(var j = rightIndex; j >= 0 && array[j] > value; j--) {
array[j + 1] = array[j];
}
array[j + 1] = value;
};
As an aside, the reason you don't need to declare j before the for loop (to be used later) is because JavaScript doesn't have block scope (TIL): See here

From the challenge:
Although there are many ways to write this function, you should write it in a way that is consistent with the hint code.
It's strictly checking for this:
var ___;
for(___ = ___; ___; ___) {
array[___ + 1] = ___;
}
So even though these two alternates are correct:
while(array[rightIndex] > value && rightIndex >= 0) {
array[rightIndex + 1] = array[rightIndex];
rightIndex--;
}
array[rightIndex + 1] = value;
And especially this almost identical one (switched the middle statement in the for loop):
for(var i = rightIndex; array[i] > value && i >= 0; i--) {
array[i + 1] = array[i];
}
array[i + 1] = value;
This one is the answer:
for(var i = rightIndex; i >= 0 && array[i] > value; i--) {
array[i + 1] = array[i];
}
array[i + 1] = value;
Ironically, it doesn't care about the useless first variable in the hint...
var ___;

No need to return the array, as it is passed by reference. Just shift every element by 1 to the right. The last statement just inserts the value at the correct position.
var insert = function(array, rightIndex, value) {
for (var i = rightIndex; array[i] >= value; i--) {
array[i+1] = array[i];
}
array[rightIndex] = value;
};

Most of the answers posted here are correct. But It does not get us to next step in Khan Academy. It could be because Khan Academy expects a certain variable name, indent settings etc. I am not exactly sure why It does not get us to next step.
This code helped me go to next step:
var insert = function(array, rightIndex, value) {
for(var j = rightIndex;
j >= 0 && array[j] > value;
j--) {
array[j + 1] = array[j];
}
array[j + 1] = value;
};
Before I discovered this code, I used i as variable name instead of j, but it did not get me to next step. But this does.

This has worked:
var insert = function(array, rightIndex, value) {
var j = rightIndex;
for(var j = rightIndex; j >= 0 && array[j] > value; j--) {
array[j + 1] = array[j];
}
array[j + 1] = value;

Related

A new sorting algorithm or a rediscovery?

I'm a novice programmer who just started learning JavaScript. While I was reading about array sorting, I came across QuickSort and looked into its algorithm. Then I thought I could come up with my own 'algorithm'.
My solution works like this. It starts by looking for the smallest and largest values and swaps them with the corner values simultaneously. It then runs recursively until both ends are equal or pass each other.
So, is this a new algorithm or a rediscovery?
This is my version of a sorting algorithm. My question is :
Do you know of any other sorting algorithm that works like this?
how can I test it's speed vis-a-vis quicksort, bubble sort...?
'use strict';
// + Name : CornerSort function for sorting arrays +
// + Author : Kedyr +
// + Date : Jan 15 , 2020 +
// + Description : The corner sort function is my first shot at sorting +
// + algorithms.After looking into the quick sort algorithm +
// + i tried to come up with my own sorting logic.It works +
// + by finding the lowest and highest values in an array +
// + and then replacing these values with the corner values. +
// + These process continues recursively until all values are +
// + correctly sorted.Now , from what i can see i believe it +
// + to be a stable sorting algorithm.I haven't tested its +
// + sorting speed and would love it if some one did that. +
// + That is , if it is not an already known algorithm which +
// + I haven't come across yet.Whatever the case is , I am +
// + going to elaborately discuss my 'new' discovery step by +
// + step in the comments . So please bear with me . +
// + For the geniuses who created this algorith before me , +
// + (if there are any), I bow down to you dear masters. +
// + please forgive my insolence. You know I wouldn't do it +
// + intentionally . It is just that genius minds think +
// + alike . :) +
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
function cornerSort(array, startIndex = 0, endIndex = array.length - 1) {
// These checks if the function is already ordered .
if (checkOrder(array, startIndex, endIndex)) {
return;
}
// the lowest and highest values.initialised to corner values.
let lowest = array[startIndex],
highest = array[endIndex];
// Indices for the lowest and highest numbers in each recursion.
let lowIndex = startIndex,
highIndex = endIndex;
let temp;
if (startIndex >= endIndex) {
return;
}
for (let i = startIndex; i <= endIndex; i++) {
if (array[i] >= highest) {
//'or-equal-to' is added to ensure the sorting doesn't change the
//order of equal numbers.Thus , a stable sorting algorithm.
highest = array[i];
highIndex = i;
}
if (array[i] < lowest) {
lowest = array[i];
lowIndex = i;
}
}
// A PRECAUTION 'IF' : for when the highest number is at the beginning of the array.
if (highIndex == startIndex) {
highIndex = lowIndex;
}
// The opposite case , lowest number at the end of array ; doesn't cause any issues.
if (lowIndex != startIndex) {
temp = array[startIndex];
array[startIndex] = array[lowIndex];
array[lowIndex] = temp;
}
if (endIndex != highIndex) {
temp = array[endIndex];
array[endIndex] = array[highIndex];
array[highIndex] = temp;
}
cornerSort(array, ++startIndex, --endIndex);
return array;
}
// The CHECKORDER function checks if the array is actually sorted so as to avoid
// unnecessary rounds of recursion.
function checkOrder(array, startIndex, endIndex) {
let unsortedCount = 0; // count of cases where array[i] > array[i+1].
for (let i = startIndex; i <= endIndex; i++) {
if (array[i] > array[i + 1]) {
unsortedCount++;
}
}
if (!unsortedCount) {
return true;
}
return false;
}
//..............................................................................
It's certainly not impossible to invent a genuinely new sorting algorithm, since there are so many different possible ways to sort. However, your algorithm exists: it is called double-ended selection sort.
Selection sort works by iteratively selecting the smallest element in the unsorted part of the array, and swapping it into place. Your algorithm is a variation of selection sort because it also selects the largest element in the unsorted part of the array and swaps that into place in the same iteration of the outer loop. This means the unsorted part is a middle segment rather than an end segment of the array.
Your implementation is also quite a lot more complicated than it needs to be: here's a simplified version which should be very slightly more efficient due to the else if in the inner loop. An element cannot be both lower than lowest and higher than highest. Since we're scanning for both the lowest and highest elements, it's also possible to detect when the "unsorted" part of the array is constant (i.e. all its values are the same) and break early.
function doubleEndedSelectionSort(arr) {
for(var i = 0, j = arr.length - 1; i < j; i++, j--) {
var minIdx = i, maxIdx = i;
var lowest = arr[minIdx], highest = arr[maxIdx];
for(var k = i + 1; k <= j; k++) {
var value = arr[k];
if(value < lowest) {
minIdx = k;
lowest = value;
} else if(value > highest) {
maxIdx = k;
highest = value;
}
}
if(minIdx === maxIdx) { break; } // the "unsorted" part of the array is constant
var iValue = arr[i], jValue = arr[j];
arr[minIdx] = iValue;
arr[i] = lowest;
arr[maxIdx] = jValue;
arr[j] = highest;
}
}
Regarding performance, the time complexity of the algorithm is the same as selection sort's O(n²), because it still has nested loops which iterate O(n) times each. In your implementation, the outer loop is replaced with recursion, but it still recurses O(n) times, so the effect is the same. That means for large enough inputs it will perform worse than O(n log n) sorting algorithms such as quicksort, merge sort, or heap sort.
Before I start, I'd suggest that this is probably more appropriate for computer science
I can't really say whether or not this is a new sorting algorithm; I think for someone to answer such a question they'd need to have a fairly comprehensive knowledge of sorting algorithms, as there are quite a few.
What I can demonstrate is how to compare performance. You'd need to do something similar in other languages, if you want to test those, and this only tests the first implementations of each I could find on the internet.
To properly understand the speed of the algorithm you have, you'd probably need to find a way to describe how it performs in different circumstances; I understand this normally involves a relatively mathematical description of the algorithm; perhaps someone with more computer science knowledge could fill in that gap.
But, despite those provisos, here's something that can work in stack overflow:
function cornerSort(array, startIndex = 0, endIndex = array.length - 1) {
// These checks if the function is already ordered .
if (checkOrder(array, startIndex, endIndex)) {
return;
}
// the lowest and highest values.initialised to corner values.
let lowest = array[startIndex],
highest = array[endIndex];
// Indices for the lowest and highest numbers in each recursion.
let lowIndex = startIndex,
highIndex = endIndex;
let temp;
if (startIndex >= endIndex) {
return;
}
for (let i = startIndex; i <= endIndex; i++) {
if (array[i] >= highest) {
//'or-equal-to' is added to ensure the sorting doesn't change the
//order of equal numbers.Thus , a stable sorting algorithm.
highest = array[i];
highIndex = i;
}
if (array[i] < lowest) {
lowest = array[i];
lowIndex = i;
}
}
// A PRECAUTION 'IF' : for when the highest number is at the beginning of the array.
if (highIndex == startIndex) {
highIndex = lowIndex;
}
// The opposite case , lowest number at the end of array ; doesn't cause any issues.
if (lowIndex != startIndex) {
temp = array[startIndex];
array[startIndex] = array[lowIndex];
array[lowIndex] = temp;
}
if (endIndex != highIndex) {
temp = array[endIndex];
array[endIndex] = array[highIndex];
array[highIndex] = temp;
}
cornerSort(array, ++startIndex, --endIndex);
return array;
}
// The CHECKORDER function checks if the array is actually sorted so as to avoid
// unnecessary rounds of recursion.
function checkOrder(array, startIndex, endIndex) {
let unsortedCount = 0; // count of cases where array[i] > array[i+1].
for (let i = startIndex; i <= endIndex; i++) {
if (array[i] > array[i + 1]) {
unsortedCount++;
}
}
if (!unsortedCount) {
return true;
}
return false;
}
function bubbleSort(a) {
var swapped;
do {
swapped = false;
for (var i=0; i < a.length-1; i++) {
if (a[i] > a[i+1]) {
var temp = a[i];
a[i] = a[i+1];
a[i+1] = temp;
swapped = true;
}
}
} while (swapped);
}
function swap(items, leftIndex, rightIndex){
var temp = items[leftIndex];
items[leftIndex] = items[rightIndex];
items[rightIndex] = temp;
}
function partition(items, left, right) {
var pivot = items[Math.floor((right + left) / 2)], //middle element
i = left, //left pointer
j = right; //right pointer
while (i <= j) {
while (items[i] < pivot) {
i++;
}
while (items[j] > pivot) {
j--;
}
if (i <= j) {
swap(items, i, j); //sawpping two elements
i++;
j--;
}
}
return i;
}
function quickSort(items, left, right) {
var index;
if (items.length > 1) {
index = partition(items, left, right); //index returned from partition
if (left < index - 1) { //more elements on the left side of the pivot
quickSort(items, left, index - 1);
}
if (index < right) { //more elements on the right side of the pivot
quickSort(items, index, right);
}
}
return items;
}
const testData = [...Array(10000).keys()].map(x => Math.random() * 1000)
console.time('corner')
const x = cornerSort(testData);
console.timeEnd('corner')
console.time('bubble')
const y = bubbleSort(testData);
console.timeEnd('bubble')
console.time('quick')
const z = quickSort(testData);
console.timeEnd('quick')

What's the problem with this implementation of selection sort?

I am learning selection sort.
I am getting the correct output for some values, but not for all the values, don't know why??
Please find below code snippet:
function selectionSortRecursion(arr,p){
if( arr.length === 1){
return p;
}
min=arr[0];
for(var i =0;i<arr.length;i++){
if (arr[i]<min){
min = arr[i];
var minIdx=i;
}
}
temp=arr[0];
arr[0]=arr[minIdx];
arr[minIdx]=temp;
p.push(arr.shift());
return selectionSortRecursion(arr,p);
}
console.log(selectionSortRecursion([2,3,5,-3,20,0,2,6,-23],[]));
The problem is that the variable minIdx is not declared unless the body of the if statement inside the loop is executed. If the minimum element is at index 0, then arr[i] < min is never true and minIdx is undefined.
To solve it, write var minIdx = 0; before the loop, since min is initialised as the value at index 0. A couple of your other variables should be declared with var, too:
function selectionSortRecursion(arr, p) {
if(arr.length === 0) {
return p;
}
var min = arr[0];
var minIdx = 0;
for(var i = 1; i < arr.length; i++) {
if (arr[i] < min) {
min = arr[i];
minIdx = i;
}
}
var temp = arr[0];
arr[0] = arr[minIdx];
arr[minIdx] = temp;
p.push(arr.shift());
return selectionSortRecursion(arr, p);
}
Note that I've also changed the loop variable i to start at 1, since there's no need to compare index 0 with itself; and the base case of the recursion should be when arr.length is 0, not 1, to avoid losing the last element.

reading 2D array behavior issue?

Test Cases:
(6, [1,3,2,6,1,2]) returns (pairs / 2) = 5
It does get the answer the thing is that is doing more than it needs to, It is possible just add some validation to know when he is adding same reversed index but it will only give it more to do. am looking to remove the unneeded work. can it be more reliable?
function returnOcurrences(k,ar){
debugger;
const letters = [new Set(ar)];
let pairs = 0;
for (let i = 0; i < ar.length; i++) {
for (let ii = 0; ii < ar.length; ii++) {
let a = ar[i] + ar[ii];
if (i != ii) {
if (a >= k) {
pairs += (a % k == 0) ? 1 : 0
}
}
}
}
return pairs/2;
}
What I assume you want to do is prevent the algorithm from checking e.g. ar[1] + ar[2], then ar[2] + ar[1] again.
To solve this, consider starting your inner loop from i + 1 and not from 0. This prevents the mentioned scenario from happening, and also prevents the algorithm from summing an element with itself (e.g. ar[0] + ar[0]). So no need to check anymore if i is equal to ii.
Why so? Assume the first iteration of the outer loop. You are checking the sum of ar[0] with ar[1], then with ar[2], ar[3], and so on.
On the second iteration of the outer loop, you are checking sums of ar[1] with other elements of the array. However, you already checked ar[0] + ar[1] in the previous iteration. So you start with ar[1] + ar[2], where ii = i + 1 = 2.
So the code becomes:
function returnOcurrences(k,ar){
const letters = [new Set(ar)]; //I don't see the purpose of this variable but okay
var pairs = 0;
for (var i = 0; i < ar.length; i++) {
for (var ii = i + 1; ii < ar.length; ii++) {
var a = ar[i] + ar[ii];
if (a >= k) {
pairs += (a % k == 0) ? 1 : 0
}
}
}
return pairs/2;
}
Hope this helps!

quick sort in javascript

I have this working insertion sort javascript code.
Array.prototype.insertionSort = function() {
var A = this;
var time = 0;
var n = A.length;
for (var i = 1; i < n; i++) {
var v = A[i];
var j = i-1;
while (j >= 0 && A[j] > v) {
A[j+1] = A[j];
j--;
var temp = new Array(this);
setTimeout(callback(JSON.stringify(temp)), 500*(time++));
}
A[j+1] = v;
var temp = new Array(this);
setTimeout(callback(JSON.stringify(temp)), 500*(time++));
}
return time;
}
I need something similar for quciksort, but I don't know how to do it. Can someone help me, please?
This might be the late posting, but I hope this may help somebody. QuickSort is a Divide and Conquer algorithm. It picks an element as pivot and partitions the given array around the picked pivot. You can select pivot in the following ways.
a)pick the first element as the pivot(Implemented below) b)pick the last element as pivot c)Pick a random element as pivot.d)pick median as a pivot.
if your array is already sorted then time complexity would be O(n^2) but for the average and best case it is O(N log N). It is in place algorithm and nonstable(as partitioning does one of the long-range exchanges). In some cases quicksort might take quadratic time. Quicksort has more overhead even for tiny arrays for sizes less than 10-20. If you use insertion sort for the small size of arrays then you might reduce the processing time by 15-20 %. Sharing my code below, also if you want to reduce more processing time then try to estimate partitioning element to be middle of an array.
class QuickSort{
constructor(){
this.cutoff = 10;
}
partition(arr, lo, hi){
let i = lo, j = hi+1;
debugger;
while(true){
while(arr[++i] < arr[lo]) if(i == hi) break;
while(arr[lo] < arr[--j]) if(j == lo) break;
if(i >= j) break;
this.swap(arr, i, j);
}
this.swap(arr, lo, j);
return j;
}
swap(arr, i, j){
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
sort(arr, lo, hi){
//if(hi <= lo) return;
if((this.cutoff + lo) -1 >= hi){
let insertionSort = new InsertionSort();
insertionSort.sort(arr); return;
}
console.log('Inside Quick Sort');
let j = this.partition(arr, lo, hi);
this.sort(arr, lo, j-1);
this.sort(arr, j+1, hi);
}
shuffle(arr) {
let n = arr.length;
for (let i = 0; i < n; i++) {
// choose index uniformly in [0, i]
let r = Math.floor(Math.random() * (i + 1));
this.swap(arr, i, r);
}
console.log('After uniform random Shuffle');
console.log(arr);
this.sort(arr, 0, n-1);
}
}
class InsertionSort{
constructor(){
this.quickSort = new QuickSort();
}
sort(arr){
console.log("Inside Insertion sort");
for(let i = 1; i < arr.length; i++){
for(let j = i; j > 0; j--){
if(arr[j-1] > arr[j]){
this.quickSort.swap(arr, j, j-1);
}
}
}
}
}
let arr = [101, 22,4,22,2,7,9,10,49,101,-1,4,1,6,99];
console.log('Before sorting an array');
console.log(arr);
let quickSort = new QuickSort();
quickSort.shuffle(arr);
console.log('After Sorting an array');
console.log(arr);
you can get to know the time complexity of from this post time complexity
The Wikipedia article on Quick Sort is pretty thorough and even includes a few pseudocode implementations.
Wikipedia summarizes the problem like so:
Quicksort is a divide and conquer algorithm. Quicksort first divides a
large array into two smaller sub-arrays: the low elements and the high
elements. Quicksort can then recursively sort the sub-arrays.
The steps are:
Pick an element, called a pivot, from the array.
Partitioning: reorder the array so that all elements with values less than the pivot come before the pivot, while all elements with values greater than the pivot come after it (equal values can go either way). After this partitioning, the pivot is in its final position. This is called the partition operation.
Recursively apply the above steps to the sub-array of elements with smaller values and separately to the sub-array of elements with greater values.
The base case of the recursion is arrays of size zero or one, which are in order by definition, so they never need to be sorted.
The pivot selection and partitioning steps can be done in several
different ways; the choice of specific implementation schemes greatly
affects the algorithm's performance.
And just a heads-up, I remember off-by-one errors being the biggest headache with this problem when I did it in school, so if you don't get the right answer right away, double-check your pivot selection and partitioning logic.
You should check google before posting a question: Quicksort is a very common algorithm and you have plenty of resources describing it.
function swap(items, firstIndex, secondIndex){
var temp = items[firstIndex];
items[firstIndex] = items[secondIndex];
items[secondIndex] = temp;
}
function partition(items, left, right) {
var pivot = items[Math.floor((right + left) / 2)],
i = left,
j = right;
while (i <= j) {
while (items[i] < pivot) {
i++;
}
while (items[j] > pivot) {
j--;
}
if (i <= j) {
swap(items, i, j);
i++;
j--;
}
}
return i;
}
function quickSort(items, left, right) {
var index;
if (items.length > 1) {
left = typeof left != "number" ? 0 : left;
right = typeof right != "number" ? items.length - 1 : right;
index = partition(items, left, right);
if (left < index - 1) {
quickSort(items, left, index - 1);
}
if (index < right) {
quickSort(items, index, right);
}
}
return items;
}
// first call
var result = quickSort(items);
Code credits: N.C.Zakas
Furthermore, note that Quicksort is used by V8 when calling Array.prototype.sort() on arrays > 10 items (V8 source). On smaller arrays, InsertionShort is actually faster.
heres a short version of quick sort written in pure JS!
as seen in Intro To Algorithms
var partition = function (arr, low, high) {
var x = arr[high]
var i = low - 1
for (var j = low; j <= high - 1; j++) {
if (arr[j] <= x) {
i++
var temp = arr[i]
arr[i] = arr[j]
arr[j] = temp
}
}
var temp = arr[i + 1]
arr[i + 1] = arr[high]
arr[high] = temp
return i + 1
}
var quickSort = function (arr, low, high) {
if (low < high) {
index = partition(arr,low,high)
if (low < index-1) quickSort(arr,low,index-1)
if (index+1 < high) quickSort(arr,index+1,high)
}
}
var list2 = [1000,13,12,1001,82,1,2,4,3,0]
console.log(quickSort(list2,0,list2.length))
also on my GitHub

function is returning numbers instead of letters

I am trying to make a function that will return the last letter of each word in a string, and think I am close, but whenever I invoke the function, I get a series of numbers instead of the letters I am looking for.
This is the code:
function lastLetter(str){
var arr = [];
for(var i = 0; i < str.length; i++){
if(str[i] === " " || str[i] === "."){
arr.push((i) - 1);
}
}
return arr;
}
lastLetter("I love bacon and eggs.");
Any advice would be appreciated. Thanks!!
You push the value i - 1 onto the array. You meant to push str.charAt(i-1):
arr.push(str.charAt(i - 1));
See: String charAt().
Note that your code isn't really defensive. If there is a space or period at the first character in the string, you are referencing the character at position -1, which is not valid. You could solve this by looping from 1 instead of 0. In that case you would still get a space in the result if the string starts with two spaces, but at least you won't get an error. A slightly better version of the algorithm would test if i-1 is a valid index, and if there is a character at that position that is not a space or a period.
Below is a possible solution, which I think solves those cases, while still retaining the structure of the code as you set it up.
function lastLetter(str){
var arr = [];
for(var i = 1; i < str.length; i++){
var p = str.charAt(i-1);
var c = str.charAt(i);
if ( (c === " " || c === ".") &&
!(p === " " || p === ".") ) {
arr.push(p);
}
}
return arr;
}
console.log(lastLetter("... Do you love bacon and eggs..."));
Try:
arr.push(str[i - 1]);
This will have problems with multi-byte characters, however.
You're pushing the integer value i-1 rather than the character str[i-1].
You are pushing the index into your array. You still need to access i-1 of your string
`
` function lastLetter(str){
var arr = [];
for(var i = 0; i < str.length; i++){
if(str[i] === " " || str[i] === "."){
arr.push(str[(i) - 1]);
}
}
return arr;
}
lastLetter("I love bacon and eggs.");
Solution and Improved version below:
use arr.push(str.charAt(i - 1)) instead of arr.push((i) - 1)
(You where saving the position of the last letter, but not it's value - charAt(position) does give you the latter at the given position
charAt(): http://www.w3schools.com/jsref/jsref_charat.asp
Demo:
function lastLetter(str){
var arr = [];
for(var i = 0; i < str.length; i++){
if(str[i] === " " || str[i] === "."){
arr.push(str.charAt(i - 1));
}
}
return arr;
}
document.body.innerHTML = lastLetter("I love bacon and eggs.");
Improved Version:
function lastLetter(str) {
var arr = [];
var words = str.split(/[\s\.?!:]+/)
for (var i = 0; i < words.length; ++i) {
if (words[i].length > 0) {
var lastLetter = words[i].charAt(words[i].length - 1)
arr.push(lastLetter);
}
}
return arr;
}
document.body.innerHTML = lastLetter("... Is this: correct?! I love bacon and eggs.");

Categories