depth first traversal of a graph - javascript - javascript

I am trying to learn graphs well and implemented the following depth-first search in javascript. The DFS function is working ok, but the checkRoutes function is the source of my troubles. The checkRoutes function accepts two inputs and returns true if there is a possible path between two nodes/vertices, and false if not. it does this by starting at a node, checking the adjacency list, and then checking the adjacency lists of every item in the adjacency list via recursion.
My solution works for only one case - when you check two vertices once, but due to the way I'm storing the possibleVertices array globally, "possibleVertices" doesn't get cleared out each time. how could I push and store to the "possibleToVisit" array inside "checkRoute" instead of globally in this class? Would it be better to have this array stored on the constructor?
var possibleToVisit = [];
function dfs(v) {
this.marked[v] = true;
if (this.adj[v] !== undefined) {
console.log("visited vertex " + v);
}
for (var i = 0; i < this.adj[v].length; i++) {
var w = this.adj[v][i];
if (!this.marked[w]) {
possibleToVisit.push(w)
this.dfs(w);
}
}
console.log(possibleToVisit);
}
function checkRoute(v, v2) {
this.dfs(v);
if (possibleToVisit.indexOf(v2) === -1) {
return false;
}
return true;
}
g = new Graph(5);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 3);
g.addEdge(2, 4);
// g.showGraph();
// g.dfs(0);
console.log(g.checkRoute(0, 4));//true
console.log(g.checkRoute(0, 5));//false
https://jsfiddle.net/youngfreezy/t1ora6ab/3/#update

You can write a DFS "starter" function, which will reset all variables, and return something if necessary:
function Graph(v) {
this.startDfs = startDfs;
this.possibleToVisit = [];
}
// ...
function startDfs(v) {
this.possibleToVisit = []; // here, you can reset any values
this.dfs(v);
return true; // here, you can return a custom object containing 'possibleToVisit'
}
And call it only using startDfs:
function checkRoute(v, v2) {
this.startDfs(v);
if (this.possibleToVisit.indexOf(v2) === -1) {
return false;
}
return true;
}
Here is the updated JSFiddle.

Arrays in Javascript get passed as reference, so something like
function fill(a,l){
for(var i = 0;i<l;i++)
a.push(i + 10);
}
function check(idx, max){
var arr = [];
fill(arr,max);
console.log(arr[idx]); // 14
}
check(4,10)
would work and everytime check gets called arr is fresh and clean.

You can use a marked[] array (which is filled up during the dfs() call) to determine whether a particular vertex can be reached from a known vertex s.
Please take a look at the depth first search implementation in the following library:
https://github.com/chen0040/js-graph-algorithms
It provides an object oriented approach to the graph creation as well as the depth first search algorithm.
The sample code for its depth first search algorithm is given here:
var jsgraphs = require('js-graph-algorithms');
var g = new jsgraphs.Graph(6);
g.addEdge(0, 5);
g.addEdge(2, 4);
g.addEdge(2, 3);
g.addEdge(1, 2);
g.addEdge(0, 1);
g.addEdge(3, 4);
g.addEdge(3, 5);
g.addEdge(0, 2);
var starting_vertex = 0;
var dfs = new jsgraphs.DepthFirstSearch(g, starting_vertex);
for(var v=1; v < g.V; ++v) {
if(dfs.hasPathTo(v)) {
console.log(s + " is connected to " + v);
console.log("path: " + dfs.pathTo(v));
} else {
console.log('No path from ' + s + ' to ' + v);
}
}

Related

Generating an array with 3 unique numbers

I'm trying to create an array with three unique random numbers between 1 and 14. I've found similar questions on Stackoverflow and used the code to help me create my existing code.
It works well most of the time, but occasionaly it will create an array with two of the same numbers. Here is the offending code:
function noDuplicates (sideRandom) {
sideArray.splice(sideRandom, 1);
let sideRandom2 = Math.floor(Math.random() * 14) + 1;
sideArray.push(sideRandom2);
console.log("I've had to add " + sideRandom2)
}
function sortNumbers(array) {
array.sort(function(a, b) {
return a - b;
});
}
document.getElementById("randomiser").addEventListener("click", function () {
for (let i = 0; sideArray.length <3; i++) {
let sideRandom = Math.floor(Math.random() * 14) + 1;
console.log(sideRandom);
if (sideArray.includes(sideRandom) === false) {
sideArray.push(sideRandom);
} else {
noDuplicates(sideRandom);
};
}
console.log(sideArray);
});
I suspect the issue is that sometimes the noDuplicates function generates the same random number as sideRandom, but I can't see a way around it. can you help?
Use set with while loop to make sure we got required number of unique random numbers
// Get unique random indexes
const random = (num, count) => {
const set = new Set();
while (set.size < count) {
set.add(Math.floor(Math.random() * num) + 1);
}
return [...set];
};
document.getElementById("randomiser").addEventListener("click", function () {
console.log(random(14, 3));
});
<button id="randomiser"> Get 3 random </button>
I take a look at your code: If there is a double you call noDuplicates and try to get a non double number but there you make some mistakes.
Why using Array#splice method? It will return the array without the first element (you don't user this result) and leave the original unchanged. So this line does anything. By the way why you want to delete the first element, youz didn't add the double random-number so there is anything do delete.
Afterwards you build another new randomnumber and push it to your array without checking. By this you get your dublettes.
Better way: If you finf a double set a flag on true and when you next add a number by this you can add your hint and reset the flag to false. So everything is one function.
document.getElementById("randomiser").addEventListener("click", function () {
let sideArray = [];
let double = false;
for (let i= 0; sideArray.length <3; i++) {
let sideRandom = Math.floor(Math.random() * 14) + 1;
console.log(sideRandom);
if (sideArray.includes(sideRandom) === false) {
if (double) {
double = false;
console.log("I've had to add " + sideRandom);
}
sideArray.push(sideRandom);
} else {
double = true;
}
}
console.log(sideArray.toString());
});
<button id='randomiser'>Click</button>
You can do this pretty easily with rando.js and slice. Plus, it's human-readable and cryptographically secure. randoSequence(1, 14) creates a shuffled array of all numbers from 1 through 14, and slice(0, 3) slices out the first three values from that shuffled array.
console.log(randoSequence(1, 14).slice(0, 3));
<script src="https://randojs.com/2.0.0.js"></script>

JavaScript: Recursive Async / Promise Based Function

I have the following recursive function that works beautifully when the output from transformItem is synchronous, but I've been having a very difficult time figuring out how to refactor it when transformItem returns a a promise and still get the same type of desired final object output.
function transformStack(target, stack){
var stackItem = stack.shift();//Copy Value
util.logData(_this.context, "Target:" + JSON.stringify(target) + " Stack:" + JSON.stringify(stack), 9);
switch(stackItem){
case "[]":
for(var x=0; x < target.length; x++){
//Copies values so not by Ref any more
var nextTarget = JSON.parse(JSON.stringify(target[x]));
if(stack.length > 0){
util.logData(_this.context, "Loop[]:" + JSON.stringify(nextTarget), 8);
target[x] = transformStack(nextTarget, JSON.parse(JSON.stringify(stack)));
} else {
util.logData(_this.context, "TransformTarget[]:" + JSON.stringify(nextTarget), 8);
target[x] = transformItem(nextTarget);
}
}
break;
default:
//Copies values so not by Ref any more
var nextTarget = JSON.parse(JSON.stringify(target[stackItem]));
if(stack.length > 0){
util.logData(_this.context, "Loop:" + JSON.stringify(nextTarget), 8);
target[stackItem] = transformStack(nextTarget, JSON.parse(JSON.stringify(stack)));
} else {
util.logData(_this.context, "TransformTarget:" + JSON.stringify(nextTarget), 8);
target[stackItem] = transformItem(nextTarget);
}
}
return target;
}
I created this base JSFiddle which illustrates this a little better on what I'm expecting:
https://jsfiddle.net/fxay76k8/9/
Can anyone help point me in the right direction? I've been looking at the following Stack Overflow post, but haven't been able to apply it properly to my flow:
JavaScript : Calling Recursive Functions With Promises
Thank-you for your help!
BTW, I'm using Q for the promises, but I'm pretty confident I can translate any other promise libraries over to what I need if someone can help me with the concepts here.
I was able to get this working with the following refactored code:
function transformStack(target, stack){
var stackItem = stack.shift();//Copy Value
var targetCopy = JSON.parse(JSON.stringify(target));
var stackCopy = JSON.parse(JSON.stringify(stack));
if(stackItem === "[]"){
return transformStackArray(targetCopy, stackCopy);
}
var nextTarget = targetCopy[stackItem];
if (stack.length > 0)
return transformStack(nextTarget, stackCopy).then(handleResponse.bind(this,target, stackItem));
else
return transformItem(nextTarget).then(handleResponse.bind(this,target, stackItem));
}
/**
* handleResponse - Helper function for merging objects for recursive function.
* #param original - The original passed value
* #param attribute - The name of the field to send
* #param updated - The updated value
* #returns {*} - Promise - Resolves to the merged object
*/
function handleResponse(original, attribute, updated){
original[attribute] = updated;
return q(original);
}
function transformStackArray(target, stack){
var deferred = q.defer();
var promises = [];
for(var x=0; x < target.length; x++){
var nextTarget = JSON.parse(JSON.stringify(target[x])); //Copies values so not by Ref any more
if(stack.length > 0){
promises.push(transformStack(nextTarget, JSON.parse(JSON.stringify(stack))));
} else {
promises.push(transformItem(nextTarget));
}
}
q.all(promises).then(function(updatedItem){
deferred.resolve(updatedItem);
}).catch(function(error){
deferred.reject(error);
});
return deferred.promise;
}
The big piece for me was wrapping my head around how to merge the objects as the new values go up the recursion. This is handles by handleResponse.
Now that I have this answer, how the linked StackOverflow relates makes a ton of sense but for some reason I had a really difficult time wrapping my head around this problem at first.

Restore Binary Tree with PreOrder and InOrder - Javascript

Could somebody teach me how to restore a binary tree using Prorder and Inorder arrays. I've seen some examples (none in JavaScript) and they kind of make sense but the recursive call never returns a full tree when I try and write. Would love to see explanations as well. Here's some code to start off:
Creating a tree node uses this:
function Tree(x) {
this.value = x;
this.left = null;
this.right = null;
}
Creating the tree uses this:
function retoreBinaryTree(inorder, preorder) {
}
Some sample input:
inorder = [4,2,1,5,3]
preorder = [1,2,4,3,5,6]
inorder = [4,11,8,7,9,2,1,5,3,6]
preorder = [1,2,4,11,7,8,9,3,5,6]
EDIT I had been working on this for days and was unable to come up with a solution of my own so I searched some out (most were written in Java). I tried to mimic this solution but to no avail.
This is a solution in C++ which I think you could translate without problem:
/* keys are between l_p and r_p in the preorder array
keys are between l_i and r_i in the inorder array
*/
Node * build_tree(int preorder[], long l_p, long r_p,
int inorder[], long l_i, long r_i)
{
if (l_p > r_p)
return nullptr; // arrays sections are empty
Node * root = new Node(preorder[l_p]); // root is first key in preorder
if (r_p == l_p)
return root; // the array section has only a node
// search in the inorder array the position of the root
int i = 0;
for (int j = l_i; j <= r_i; ++j)
if (inorder[j] == preorder[l_p])
{
i = j - l_i;
break;
}
root->left = build_tree(preorder, l_p + 1, l_p + i,
inorder, l_i, l_i + (i - 1));
root->right = build_tree(preorder, l_p + i + 1, r_p,
inorder, l_i + i + 1, r_i);
return root;
}

How to add up numbers in a nested array javascript

Just working on a project and tried a few different solutions but with no results. Could someone help me with how to add up numbers in a nested array? Would I use reduce? or a for loop?
function balance(arr) {
if(typeof item == 'number') {
return arr;enter code here
} else {
return arr + balance(item);
}
}
Is this maybe what you are hoping for?
function balance(arr) {
return arr.reduce(function(sum, item) {
if(typeof item == 'number') {
return sum;
} else {
return sum + balance(item);
}
},0);
}
console.log(balance([1,2,[3,4],5]));
Just for the record (to disprove the assertion that recursion is required), here's a version that uses a sequential algorithm. Recursion is concise and (usually) easier to read, however if speed matters, it can be slow. However, based on results from jsPerf, script engines seem very much better at optimising recursive code than they used to be, at least for simple programs like this.
For comparison, I've included a recursive version using a plain loop, the jsPerf tests also include a (fixed) recursive version using reduce. I suspect Any's answer will be slowest as it calls slice and itself on every loop, but I didn't have time to fix it.
So I guess recursion is fine here as it is fast and concise.
/* Sum the values of nested arrays. Only checks if values are arrays,
** otherwise assumes they're numbers
**
** #param {Array} arr - array of numbers to process, may have
** nested arrays of numbers
** #returns {number} - sum of values or NaN if arr is not an Array
*/
function balance(arr) {
// Only process arrays
var isArray = Array.isArray;
if (!isArray(arr)) return NaN;
// Setup
var arrays = [], indexes = [];
var currentArray = arr;
var currentValue;
var sum = 0;
var i = 0, iLen = arr.length;
// Use <= length as must handle end of array inside loop
while (i <= iLen || arrays.length) {
currentValue = currentArray[i];
// If at end of current array, reset value to before entering array
// Reset i to previous value as will increment at the bottom
if (i == currentArray.length && arrays.length) {
currentArray = arrays.pop();
i = indexes.pop();
iLen = currentArray.length;
// If current value is an array, use it and reset loop control values
// set i to -1 as will increment at the bottom
} else if (isArray(currentValue)) {
arrays.push(currentArray);
indexes.push(i);
currentArray = currentValue;
i = -1;
iLen = currentArray.length;
// Otherwise, add the current value
// Will be undefined if at end of array so add zero
} else {
sum += +currentValue || 0;
}
// Increment i
i++;
}
return sum;
}
document.write(
'balance sequential 1: ' +
balance([1,[2,1,[1,2,-1],[1]],1,[2,1]]) // 11
+ '<br>balance sequential 2: ' +
balance([1,2,[3,4],5]) // 15
);
/* Sum the values of nested arrays. Only checks if values are arrays,
** otherwise assumes they're numbers
**
** #param {Array} arr - array of numbers to process, may have
** nested arrays of numbers
** #returns {number} - sum of values or NaN if arr is not an Array
*/
function balanceLoop(arr) {
if (!Array.isArray(arr)) return NaN;
for (var value, total=0, i=0, iLen=arr.length; i<iLen; i++) {
value = arr[i];
total += Array.isArray(value)? balanceLoop(value) : value;
}
return total;
}
document.write(
'<br>balanceLoop 1: ' +
balanceLoop([1,[2,1,[1,2,-1],[1]],1,[2,1]]) // 11
+ '<br>balanceLoop 2: ' +
balanceLoop([1,2,[3,4],5]) // 15
);
A simple recursive function:
function balance(arr, total) {
total = total || 0;
if (arr.length === 0) return total;
var head = arr[0];
if (typeof head === 'number') {
return balance(arr.slice(1), total += head);
} else {
return balance(head, total);
}
}
balance([1, [2, 1, 3, [43, 2]]])); // 52
DEMO
I would probably solve this using a recursive reduce, in the following manner:
function balance(arr) {
return arr.reduce(function(sum,item) {
return sum + (item instanceof Array ? balance(item) : item);
}, 0);
};
balance([1,[2,1,[1,2,-1],[1]],1,[2,1]]); // 11
If you don't mind the overhead, you could of course do this:
Number.prototype.balance = function() { return this; };
Array.prototype.balance = function() { return this.reduce(function(a,b) { return a + b.balance(); }, 0); }
[1,[2,1,[1,2,-1],[1]],1,[2,1]].balance(); // 11

Random Number with javascript or jquery

I am trying to make a script to pick random number between two numbers . but it picks same number sometimes. i donot want to repeat same number until array is finished .
Here is my code
$(document).ready(function () {
abc();
test = array();
function abc() {
res = randomXToY(1, 10, 0);
$('#img' + res).fadeTo(1200, 1);
//$(this).addClass('activeImg');
//});
setTimeout(function () {
removeClassImg(res)
}, 3000);
}
function removeClassImg(res) {
$('#img' + res).fadeTo(1200, 0.1);
//$('#img' + res).removeClass('activeImg');
abc();
}
function randomXToY(minVal, maxVal, floatVal) {
var randVal = minVal + (Math.random() * (maxVal - minVal));
return typeof floatVal == 'undefined' ? Math.round(randVal) : randVal.toFixed(floatVal);
}
});
Does Anybody have idea about this ...
You'll have to maintain a list of numbers that have already been generated, and check against this list. Re-generate a new number if you find a dupe.
If you do not want the random numbers repeating themselves you have to keep track of the some way.
If you have the range you are dealing with is relatively small, you can create an array with all possible results and simply randomly pick out of it.
function Randomizer(minVal, maxVal, floatVal){
var possible_results = []; // for larger arrays you can build this using a loop of course
var randomization_array = [];
var count = minVal;
var incrementor = floatVal || 1; // set the distance between possible values (if floatVal equals 0 we round to 1)
while (count <= maxVal) {
possible_results.push(count);
count += incrementor;
}
this.run = function(){
// if randomization_array is empty set posssible results into it
randomization_array = randomization_array.length ? randomization_array : $.merge(randomization_array, possible_results);
// pick a random element within the array
var rand = Math.floor(Math.random()*randomization_array.length);
// return the relevant element
return randomization_array.splice(rand,1)[0];
}
}
and in order to use it (it creates a specialized object for each possible range):
rand = new Randomizer(1,10,0);
rand.run();
note that this approach does not work well for very large ranges

Categories

Resources