PHP of data structure and algorithm using adjacency table and adjacency matrix to realize depth first traversal (DFS) of graph

Keywords: PHP

1, Basic ideas
1) Access the specified starting vertex v;
2) From the adjacency point of v which is not visited, the graph is traversed in depth first, until the vertices which have path communication with v are visited;
3) If there are still vertices in the graph that have not been visited at this time, the depth first traversal is carried out again from a vertex that has not been visited until all the vertices in the graph have been visited.
 
2, Storage structure of Graphs
                     Adjacency table storage mode of example graph adjacency matrix storage mode of graph
 
3, Implementation mode
1. Adjacency table
<?php
/**
 * Depth first traversal of Graphs
 * The storage structure of graph adjacency table
 */
class Node{
    public $value = null;
    public $next = [];//An array that stores the location of the next node

    public function __construct($value = null){
        $this->value = $value;
    }
}

class Graph
{
    // Record whether the node has been traversed
    public $visited = [];
    // Adjacency table array of Graphs
    public $graph = [];

    /**
     * Add adjacency points to vertices
     * @param $vertex Vertex v
     * @param $adjvex Adjacency point of vertex v
     */
    public function addVertex($vertex, $adjvex)
    {
        $this->graph[$vertex][] = $adjvex;
    }

    // Convert adjacency list array to adjacency list
    public function createGraph()
    {
        $vertices = array_keys($this->graph);
        $result = [];
        foreach ($vertices as $vertex) {
            $result[$vertex] = new Node($vertex);
        }
        foreach ($this->graph as $vertex => $adjvex) {
            foreach ($adjvex as $v) {
                if (isset($result[$v]) && is_object($result[$v])) {
                    $result[$vertex]->next[] = $result[$v];
                }
            }
        }
        return $result;
    }

    /**
     * recursion
     * @param $v The first vertex to be accessed is passed in
     */
    public function dfs($v) {
        // Set visited flag
        $this->visited[$v] = 1;
        // Output visited vertex
        echo $v . PHP_EOL;
//        print_r($this->graph[$v]);die;
        for ($i = 0; $i < count($this->graph[$v]); $i++) {
            if ($this->visited[$this->graph[$v][$i]] == 0) {
                $this->dfs($this->graph[$v][$i]);
            } else {
                continue;
            }
        }
    }

    /**
     * non-recursive 
     * @param $v The first vertex to be accessed is passed in
     */
    public function deepFirstSearch($v) {
        // Initialize node traversal flag
        $vertices = array_keys($this->graph);
        foreach ($vertices as $vertex) {
            $this->visited[$vertex] = 0;
        }
        $stack[] = $v;
        while (!empty($stack)) {
            $current = array_pop($stack);
            if ($this->visited[$current->value] == 0) {
                echo $current->value . PHP_EOL;
                $this->visited[$current->value] = 1;
            }
            for ($i = count($current->next) - 1; $i >= 0; $i--) {
                if ($this->visited[$current->next[$i]->value] == 0) {
                    $stack[] = $current->next[$i];
                }
            }
        }
    }
}
// test
$vertices = ['v1', 'v2', 'v3', 'v4', 'v5', 'v6', 'v7', 'v8'];
$g = new Graph();
$g->addVertex('v1', 'v2');
$g->addVertex('v1', 'v3');
$g->addVertex('v2', 'v1');
$g->addVertex('v2', 'v4');
$g->addVertex('v2', 'v5');
$g->addVertex('v3', 'v1');
$g->addVertex('v3', 'v6');
$g->addVertex('v3', 'v7');
$g->addVertex('v4', 'v2');
$g->addVertex('v4', 'v8');
$g->addVertex('v5', 'v2');
$g->addVertex('v5', 'v8');
$g->addVertex('v6', 'v3');
$g->addVertex('v6', 'v7');
$g->addVertex('v7', 'v3');
$g->addVertex('v7', 'v6');
$g->addVertex('v8', 'v4');
$g->addVertex('v8', 'v5');
//print_r($g->graph);
// recursion
$g->dfs($vertices[0]);
// non-recursive 
$firstVertex = current($g->createGraph());
$g->deepFirstSearch($firstVertex);

2, Adjacency matrix

<?php
/**
 * Depth first traversal of Graphs
 * The storage structure of graph adjacency matrix
 */
class Graph {
    // Storage node information
    public $vertices;
    // Storage side information
    public $arcs;
    // Number of nodes in a graph
    public $vexnum;
    // Record whether the node has been traversed
    public $visited = [];

    // initialization
    public function __construct($vertices) {
        $this->vertices = $vertices;
        $this->vexnum = count($this->vertices);
        for ($i = 0; $i < $this->vexnum; $i++) {
            for ($j = 0; $j < $this->vexnum; $j++) {
                $this->arcs[$i][$j] = 0;
            }
        }
    }

    // Add an edge between two vertices(Undirected graph)
    public function addEdge($a, $b) {
        if ($a == $b) { // The head and tail of an edge cannot be the same node
            return;
        }
        $this->arcs[$a][$b] = 1;
        $this->arcs[$b][$a] = 1;
    }

    // From the i Nodes start depth first traversal
    public function traverse($i) {
        // Mark the i Nodes traversed
        $this->visited[$i] = 1;
        // Print the currently traversed node
        echo $this->vertices[$i] . PHP_EOL;
        // In ergodic adjacency matrix i Direct connection of nodes
        for ($j = 0; $j < $this->vexnum ; $j++) {
            // The target node is directly connected with the current node, and the node has not been accessed yet. Recursion
            if ($this->arcs[$i][$j] == 1 && $this->visited[$j] == 0) {
                $this->traverse($j);
            }
        }
    }

    // recursion
    public function dfs() {
        // Initialize node traversal flag
        for ($i = 0; $i < $this->vexnum; $i++) {
            $this->visited[$i] = 0;
        }
        // Start deep traversal from nodes not traversed
        for ($i = 0; $i < $this->vexnum; $i++) {
            if ($this->visited[$i] == 0) {
                // If it is a connected graph, it will only be executed once
                $this->traverse($i);
            }
        }
    }

    // non-recursive 
    public function deepFirstSearch() {
        // Initialize node traversal flag
        for ($i = 0; $i < $this->vexnum; $i++) {
            $this->visited[$i] = 0;
        }
        $stack = [];
        for ($i = 0; $i < $this->vexnum; $i++) {
            if (!$this->visited[$i]) {
                $stack[] = $i;
                while (!empty($stack)) {
                    // Out of the stack
                    $curr = array_pop($stack);
                    // If the node has not been traversed, traverse the node and stack the child nodes
                    if ($this->visited[$curr] == 0) {
                        echo $this->vertices[$curr] . PHP_EOL;
                        $this->visited[$curr] = 1;
                        // Non traversal child nodes are pushed
                        for ($j = $this->vexnum - 1; $j >= 0; $j--) {
                            if ($this->arcs[$curr][$j] == 1 && $this->visited[$j] == 0) {
                                $stack[] = $j;
                            }
                        }
                    }
                }
            }
        }
    }
}
// test
$vertices = ['v1', 'v2', 'v3', 'v4', 'v5', 'v6', 'v7', 'v8'];
$graph = new Graph($vertices);
$graph->addEdge(0, 1); // v1 v2
$graph->addEdge(0, 2); // v1 v3
$graph->addEdge(1, 3); // v2 v4
$graph->addEdge(1, 4); // v2 v5
$graph->addEdge(2, 5); // v3 v6
$graph->addEdge(2, 6); // v3 v7
$graph->addEdge(4, 7); // v5 v8
$graph->addEdge(3, 7); // v4 v8
// recursion
$graph->dfs();
// non-recursive 
$graph->deepFirstSearch();

Posted by novice@work on Thu, 21 May 2020 08:07:31 -0700