7

I have a particularly large graph, making it nearly impossible to traverse using recursion because of the excessive amount of memory it uses.

Below is my depth-first function, using recursion:

public function find_all_paths($start, $path)
{
    $path[] = $start;
    if (count($path)==25) /* Only want a path of maximum 25 vertices*/ {
        $this->stacks[] = $path;
        return $path;

    }
    $paths = array();

    for($i = 0; $i < count($this->graph[$start])-1; $i++) {
        if (!in_array($this->graph[$start][$i], $path)) {
     $paths[] = $this->find_all_paths($this->graph[$start][$i], $path);

        }
    }


    return $paths;
}

I would like to rewrite this function so it is non-recursive. I assume I will need to make a queue of some sort, and pop off values using array_shift() but in which part of the function, and how do I make sure the queued vertices are preserved (to put the final pathway on $this->stacks)?

Alex Shesterov
  • 26,085
  • 12
  • 82
  • 103
server_kitten
  • 386
  • 3
  • 13
  • DFS doesn't use exp. amount of memory. It only uses linear memory for the stack. – nhahtdh Mar 09 '13 at 21:09
  • 1
    Note that all recursion can be replaced by iteration thats a general thruth. The question is, if this saves memory (as @nhahtdh mentioned). If the maximum stack size or depth isn't limited, I see no advantage – hek2mgl Mar 09 '13 at 21:11
  • @nhahtdh He didn't say it takes exponential space, he said it takes *excessive* space. Which is true -- depending on what your graph looks like, DFS takes space linear in the number of *vertices*, which can (on entirely reasonable graphs) be too large for the built-in call stack, but small enough to fit into a heap-allocated data structure. –  Mar 09 '13 at 21:12
  • I did say exponential space, but I corrected myself. I was hoping an iterative function would ease the memory usage since it won't have to wait for maybe hundreds of functions to return from the bottom of the call stack. – server_kitten Mar 09 '13 at 21:17
  • @delnan: I don't know what OP is trying to do, but it seems that he (wants to) implements a depth-limited search rather than a real depth-first search (based on the comment "Only want a path of maximum 25 vertices"). – nhahtdh Mar 09 '13 at 21:18
  • Correct, I want to reach all nodes accessible within 24 moves to adjacent vertices without revisiting any, of course. ^^ – server_kitten Mar 09 '13 at 21:21
  • 6
    @PseudoOne: If anything, I suspect that you run out of memory because there are too many paths, rather than the problem with stack. – nhahtdh Mar 09 '13 at 21:24
  • that's possible. I'll try writing to a flatfile after 50,000 or so paths. – server_kitten Mar 09 '13 at 21:31
  • nhahtdh is right. Your recursion depth is limited to 25. Using an iterative approach won't help you. You probably use so much memory because you visit the nodes in your graph multiple times. Unless you really want to list every path, you should keep track which nodes you already visited and return if you hit a visited node. – nwellnhof Mar 10 '13 at 00:31
  • What is the structure .... ? – Baba Mar 29 '13 at 09:22
  • Are you interested in visiting all the edges, or merely all the nodes? – phs Apr 01 '13 at 00:36
  • All the nodes. However, for my situation I have found there are over 30 billion pathways and this won't be efficient. – server_kitten Apr 02 '13 at 23:49
  • You might want consider using `SplStack` (http://php.net/manual/en/class.splstack.php). – Kendall Hopkins Apr 21 '13 at 00:12

1 Answers1

1

It doesn't take exponential space, number of paths in a tree is equal to number of leaves, every leaf has only 1 path from the root ..

Here is a DFS simple search for an arbitrary binary tree:

// DFS: Parent-Left-Right
public function dfs_search ( $head, $key )
{
    var $stack = array($head);
    var $solution = array();

    while (count($stack) > 0)
    {
        $node = array_pop($stack);

        if ($node.val == $key)
        {
            $solution[] = $node;
        }

        if ($node.left != null)
        {
            array_push($stack, $node.left);
        }

        if ($node.right != null)
        {
            array_push($stack, $node.right);
        }
    }

    return $solution;
}

What you need to find all paths in a tree is simply Branch & Fork, meaning whenever you branch, each branch takes a copy of the current path .. here is a 1-line recursive branch & fork I wrote:

// Branch & Fork
public function dfs_branchFork ( $node, $path )
{
    return array($path)
        +($node.right!=null?dfs_branchFork($node.right, $path+array($node)):null)
        +($node.left!=null?dfs_branchFork($node.left, $path+array($node)):null);
}
Khaled.K
  • 5,828
  • 1
  • 33
  • 51