Cracking the Coding Interview - 4.1 Graph Traversal

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
0
down vote

favorite












I'm working through the classic Cracking the Coding Interview book. I'm trying to solve the following graph problem:




4.1) Route Between Nodes: Given a directed graph, design an algorithm to find out whether there is a route between two nodes.




I've written a solution in JavaScript and found it was a lot less complicated than the book's solution. Am I missing something? Why does the solution use a Visiting state? Can't we just use Visited instead?



function RouteBetweenNodes( node1, node2 ) 

const q = new Queue()
q.add( node1 )

while ( !q.isEmpty() )
const node = q.remove()
if ( node === node2 )
return true

node.visited = true
node.children.forEach( child => !child.visited && q.add( child ) )


return false




Here is an implementation of a Queue for completeness:



class QueueNode 

constructor( data )
this.data = data
this.next = null




class Queue

constructor()
this.first = null
this.last = null


add( item )
const newNode = new QueueNode( item )
if ( this.last )
this.last.next = newNode
else
this.first = newNode

this.last = newNode


remove()
if ( this.first )
const data = this.first.data
this.first = this.first.next
if ( this.first == null )
this.last == null

return data

throw Error( 'empty queue' )


peek()
if ( this.first )
return this.first.data

throw Error( 'empty queue' )


isEmpty()
return this.first === null





Here is the book's solution.







share|improve this question

















  • 1




    Welcome to Code Review! I hope you get some good answers =)
    – Phrancis
    Jun 26 at 22:07










  • The Visiting state lets you tell apart nodes waiting in the queue from the truly uncharted nodes. Without such state the same node may be added multiple times. It hurts performance, and in some (very contrived) cases may even lead to incorrectness.
    – vnp
    Jun 26 at 22:24










  • @vnp I can't see a case where it would lead to incorrect results. Can you elaborate?
    – hoffmale
    Jun 26 at 22:32










  • @hoffmale On a specially crafted infinite graph, with some nodes having infinitely many inbound edges, the algorithm would fail to find a surely existing path, whereas a book solution would succeed. Pretty contrived, as I said.
    – vnp
    Jun 26 at 22:38










  • It appears that the code in the image is Java, but your code is Javascript (or at least you used the tag javascript)... is that intentional?
    – Sam Onela
    Jun 26 at 22:40

















up vote
0
down vote

favorite












I'm working through the classic Cracking the Coding Interview book. I'm trying to solve the following graph problem:




4.1) Route Between Nodes: Given a directed graph, design an algorithm to find out whether there is a route between two nodes.




I've written a solution in JavaScript and found it was a lot less complicated than the book's solution. Am I missing something? Why does the solution use a Visiting state? Can't we just use Visited instead?



function RouteBetweenNodes( node1, node2 ) 

const q = new Queue()
q.add( node1 )

while ( !q.isEmpty() )
const node = q.remove()
if ( node === node2 )
return true

node.visited = true
node.children.forEach( child => !child.visited && q.add( child ) )


return false




Here is an implementation of a Queue for completeness:



class QueueNode 

constructor( data )
this.data = data
this.next = null




class Queue

constructor()
this.first = null
this.last = null


add( item )
const newNode = new QueueNode( item )
if ( this.last )
this.last.next = newNode
else
this.first = newNode

this.last = newNode


remove()
if ( this.first )
const data = this.first.data
this.first = this.first.next
if ( this.first == null )
this.last == null

return data

throw Error( 'empty queue' )


peek()
if ( this.first )
return this.first.data

throw Error( 'empty queue' )


isEmpty()
return this.first === null





Here is the book's solution.







share|improve this question

















  • 1




    Welcome to Code Review! I hope you get some good answers =)
    – Phrancis
    Jun 26 at 22:07










  • The Visiting state lets you tell apart nodes waiting in the queue from the truly uncharted nodes. Without such state the same node may be added multiple times. It hurts performance, and in some (very contrived) cases may even lead to incorrectness.
    – vnp
    Jun 26 at 22:24










  • @vnp I can't see a case where it would lead to incorrect results. Can you elaborate?
    – hoffmale
    Jun 26 at 22:32










  • @hoffmale On a specially crafted infinite graph, with some nodes having infinitely many inbound edges, the algorithm would fail to find a surely existing path, whereas a book solution would succeed. Pretty contrived, as I said.
    – vnp
    Jun 26 at 22:38










  • It appears that the code in the image is Java, but your code is Javascript (or at least you used the tag javascript)... is that intentional?
    – Sam Onela
    Jun 26 at 22:40













up vote
0
down vote

favorite









up vote
0
down vote

favorite











I'm working through the classic Cracking the Coding Interview book. I'm trying to solve the following graph problem:




4.1) Route Between Nodes: Given a directed graph, design an algorithm to find out whether there is a route between two nodes.




I've written a solution in JavaScript and found it was a lot less complicated than the book's solution. Am I missing something? Why does the solution use a Visiting state? Can't we just use Visited instead?



function RouteBetweenNodes( node1, node2 ) 

const q = new Queue()
q.add( node1 )

while ( !q.isEmpty() )
const node = q.remove()
if ( node === node2 )
return true

node.visited = true
node.children.forEach( child => !child.visited && q.add( child ) )


return false




Here is an implementation of a Queue for completeness:



class QueueNode 

constructor( data )
this.data = data
this.next = null




class Queue

constructor()
this.first = null
this.last = null


add( item )
const newNode = new QueueNode( item )
if ( this.last )
this.last.next = newNode
else
this.first = newNode

this.last = newNode


remove()
if ( this.first )
const data = this.first.data
this.first = this.first.next
if ( this.first == null )
this.last == null

return data

throw Error( 'empty queue' )


peek()
if ( this.first )
return this.first.data

throw Error( 'empty queue' )


isEmpty()
return this.first === null





Here is the book's solution.







share|improve this question













I'm working through the classic Cracking the Coding Interview book. I'm trying to solve the following graph problem:




4.1) Route Between Nodes: Given a directed graph, design an algorithm to find out whether there is a route between two nodes.




I've written a solution in JavaScript and found it was a lot less complicated than the book's solution. Am I missing something? Why does the solution use a Visiting state? Can't we just use Visited instead?



function RouteBetweenNodes( node1, node2 ) 

const q = new Queue()
q.add( node1 )

while ( !q.isEmpty() )
const node = q.remove()
if ( node === node2 )
return true

node.visited = true
node.children.forEach( child => !child.visited && q.add( child ) )


return false




Here is an implementation of a Queue for completeness:



class QueueNode 

constructor( data )
this.data = data
this.next = null




class Queue

constructor()
this.first = null
this.last = null


add( item )
const newNode = new QueueNode( item )
if ( this.last )
this.last.next = newNode
else
this.first = newNode

this.last = newNode


remove()
if ( this.first )
const data = this.first.data
this.first = this.first.next
if ( this.first == null )
this.last == null

return data

throw Error( 'empty queue' )


peek()
if ( this.first )
return this.first.data

throw Error( 'empty queue' )


isEmpty()
return this.first === null





Here is the book's solution.









share|improve this question












share|improve this question




share|improve this question








edited Jun 27 at 3:43
























asked Jun 26 at 21:51









Narin Luangrath

63




63







  • 1




    Welcome to Code Review! I hope you get some good answers =)
    – Phrancis
    Jun 26 at 22:07










  • The Visiting state lets you tell apart nodes waiting in the queue from the truly uncharted nodes. Without such state the same node may be added multiple times. It hurts performance, and in some (very contrived) cases may even lead to incorrectness.
    – vnp
    Jun 26 at 22:24










  • @vnp I can't see a case where it would lead to incorrect results. Can you elaborate?
    – hoffmale
    Jun 26 at 22:32










  • @hoffmale On a specially crafted infinite graph, with some nodes having infinitely many inbound edges, the algorithm would fail to find a surely existing path, whereas a book solution would succeed. Pretty contrived, as I said.
    – vnp
    Jun 26 at 22:38










  • It appears that the code in the image is Java, but your code is Javascript (or at least you used the tag javascript)... is that intentional?
    – Sam Onela
    Jun 26 at 22:40













  • 1




    Welcome to Code Review! I hope you get some good answers =)
    – Phrancis
    Jun 26 at 22:07










  • The Visiting state lets you tell apart nodes waiting in the queue from the truly uncharted nodes. Without such state the same node may be added multiple times. It hurts performance, and in some (very contrived) cases may even lead to incorrectness.
    – vnp
    Jun 26 at 22:24










  • @vnp I can't see a case where it would lead to incorrect results. Can you elaborate?
    – hoffmale
    Jun 26 at 22:32










  • @hoffmale On a specially crafted infinite graph, with some nodes having infinitely many inbound edges, the algorithm would fail to find a surely existing path, whereas a book solution would succeed. Pretty contrived, as I said.
    – vnp
    Jun 26 at 22:38










  • It appears that the code in the image is Java, but your code is Javascript (or at least you used the tag javascript)... is that intentional?
    – Sam Onela
    Jun 26 at 22:40








1




1




Welcome to Code Review! I hope you get some good answers =)
– Phrancis
Jun 26 at 22:07




Welcome to Code Review! I hope you get some good answers =)
– Phrancis
Jun 26 at 22:07












The Visiting state lets you tell apart nodes waiting in the queue from the truly uncharted nodes. Without such state the same node may be added multiple times. It hurts performance, and in some (very contrived) cases may even lead to incorrectness.
– vnp
Jun 26 at 22:24




The Visiting state lets you tell apart nodes waiting in the queue from the truly uncharted nodes. Without such state the same node may be added multiple times. It hurts performance, and in some (very contrived) cases may even lead to incorrectness.
– vnp
Jun 26 at 22:24












@vnp I can't see a case where it would lead to incorrect results. Can you elaborate?
– hoffmale
Jun 26 at 22:32




@vnp I can't see a case where it would lead to incorrect results. Can you elaborate?
– hoffmale
Jun 26 at 22:32












@hoffmale On a specially crafted infinite graph, with some nodes having infinitely many inbound edges, the algorithm would fail to find a surely existing path, whereas a book solution would succeed. Pretty contrived, as I said.
– vnp
Jun 26 at 22:38




@hoffmale On a specially crafted infinite graph, with some nodes having infinitely many inbound edges, the algorithm would fail to find a surely existing path, whereas a book solution would succeed. Pretty contrived, as I said.
– vnp
Jun 26 at 22:38












It appears that the code in the image is Java, but your code is Javascript (or at least you used the tag javascript)... is that intentional?
– Sam Onela
Jun 26 at 22:40





It appears that the code in the image is Java, but your code is Javascript (or at least you used the tag javascript)... is that intentional?
– Sam Onela
Jun 26 at 22:40











1 Answer
1






active

oldest

votes

















up vote
1
down vote



accepted











  • Your worst case performance (every node is connected to each other node but node2) is $mathcalO(n^2)$, up from the "normal" $mathcalO(n)$, because nodes can be added to the queue multiple times. This should also increase the average runtime. This gets even worse if multiple edges between any 2 nodes are allowed.



    Note that adding another check q.contains(node) would still result in a runtime of $mathcalO(n^2)$ as those checks add a factor of $mathcalO(n)$. The Visiting state prevents this.



  • visited is never reset to false (in the presented code). This will lead to errors in subsequent calls.


  • The definition of Queue is missing.






share|improve this answer























    Your Answer




    StackExchange.ifUsing("editor", function ()
    return StackExchange.using("mathjaxEditing", function ()
    StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
    StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
    );
    );
    , "mathjax-editing");

    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "196"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: false,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );








     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f197314%2fcracking-the-coding-interview-4-1-graph-traversal%23new-answer', 'question_page');

    );

    Post as a guest






























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    1
    down vote



    accepted











    • Your worst case performance (every node is connected to each other node but node2) is $mathcalO(n^2)$, up from the "normal" $mathcalO(n)$, because nodes can be added to the queue multiple times. This should also increase the average runtime. This gets even worse if multiple edges between any 2 nodes are allowed.



      Note that adding another check q.contains(node) would still result in a runtime of $mathcalO(n^2)$ as those checks add a factor of $mathcalO(n)$. The Visiting state prevents this.



    • visited is never reset to false (in the presented code). This will lead to errors in subsequent calls.


    • The definition of Queue is missing.






    share|improve this answer



























      up vote
      1
      down vote



      accepted











      • Your worst case performance (every node is connected to each other node but node2) is $mathcalO(n^2)$, up from the "normal" $mathcalO(n)$, because nodes can be added to the queue multiple times. This should also increase the average runtime. This gets even worse if multiple edges between any 2 nodes are allowed.



        Note that adding another check q.contains(node) would still result in a runtime of $mathcalO(n^2)$ as those checks add a factor of $mathcalO(n)$. The Visiting state prevents this.



      • visited is never reset to false (in the presented code). This will lead to errors in subsequent calls.


      • The definition of Queue is missing.






      share|improve this answer

























        up vote
        1
        down vote



        accepted







        up vote
        1
        down vote



        accepted







        • Your worst case performance (every node is connected to each other node but node2) is $mathcalO(n^2)$, up from the "normal" $mathcalO(n)$, because nodes can be added to the queue multiple times. This should also increase the average runtime. This gets even worse if multiple edges between any 2 nodes are allowed.



          Note that adding another check q.contains(node) would still result in a runtime of $mathcalO(n^2)$ as those checks add a factor of $mathcalO(n)$. The Visiting state prevents this.



        • visited is never reset to false (in the presented code). This will lead to errors in subsequent calls.


        • The definition of Queue is missing.






        share|improve this answer
















        • Your worst case performance (every node is connected to each other node but node2) is $mathcalO(n^2)$, up from the "normal" $mathcalO(n)$, because nodes can be added to the queue multiple times. This should also increase the average runtime. This gets even worse if multiple edges between any 2 nodes are allowed.



          Note that adding another check q.contains(node) would still result in a runtime of $mathcalO(n^2)$ as those checks add a factor of $mathcalO(n)$. The Visiting state prevents this.



        • visited is never reset to false (in the presented code). This will lead to errors in subsequent calls.


        • The definition of Queue is missing.







        share|improve this answer















        share|improve this answer



        share|improve this answer








        edited Jun 26 at 22:57


























        answered Jun 26 at 22:24









        hoffmale

        4,225630




        4,225630






















             

            draft saved


            draft discarded


























             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f197314%2fcracking-the-coding-interview-4-1-graph-traversal%23new-answer', 'question_page');

            );

            Post as a guest













































































            Popular posts from this blog

            Python Lists

            Aion

            JavaScript Array Iteration Methods