Learning data structure-Chapter 5: Graph (traversal operation of graph)

Chapter 5: Graph (traversal operation of graph)

1. Graph traversal

Graph traversal : Divide from a certain vertex in the graph, and visit all vertices in the graph sequentially and only once according to a certain search method along the edges in the graph

In fact, the hierarchical traversal of the tree is similar to the breadth-first search of the graph. You can think of this binary tree as a graph

2. Breadth First Search (BFS)

**Breadth First Search**

  • First visit the starting vertex v
  • Then, starting from v v turn each visit has not been visited adjacent vertices of w1, w1 ... wi
  • Followed by access w1, w2 ... wi all not visited adjacent vertices
  • In From these vertices visited, access all of their non-visited adjacent vertices
  • And so on

As shown above, it is 广度优先搜索遍历, if we follow 树的层次遍历traverse this way it is as follows:

First 1, then visit all its adjacent vertices, namely 2, 3, and then visit the adjacent vertices of 2 and 3, 2’s 4 and 5, and 3’s 6 respectively. Then we start from vertex 4 and still visit all its adjacent vertices, which is 7 And 5, at this time we will make an error, because we have already visited vertex 5, and revisiting does not meet the requirements of **breadth first search**, **so we cannot completely follow the tree level when we traverse The traversal method is used to traverse the graph**, so how to realize the breadth-first search of the graph?

We know that to traverse the tree level, we use a special data structure: queue

Then, as shown in the figure, we not only rely on the queue but also rely on an auxiliary marker array, namely: queue + auxiliary marker array

Auxiliary tag array

We still use the above figure, first we need to initialize, that is, set all the values ​​in the auxiliary tag array to 0, that is, 0 means that it has not been accessed, and 1 means that it has been accessed. Re-traverse: starting from 1, first enter the team, then modify v[0]=1, then leave the team first element 1 and visit, then we need to enter the adjacent vertices 2 and 3 of 1 into the team once, then modify v[1]=1,v[2]=1, and then leave the first element of the team 2 and visit, then we need to enqueue the adjacent vertices of vertex 2 respectively 1, 4, and 5, here we actually only enqueue 4 and 5, and then modify v[3]=1,v[4]=1, there is a judgment process here is to use this auxiliary marker array, Then dequeue and visit the first element 3 of the first team, and then perform the enqueue operation on the vertex adjacent to vertex 3 and the vertices that are not enqueued, that is, vertex 6 is enqueued and modified at the same time a[5]=1, and then the first element 4 of the team is dequeued and visited, and then The adjoining vertex of the enqueued vertex 4 and the unentered vertex 7 are modified at the same time v[6]=1, then the first element of the dequeue 5 and visit, then the first element of the dequeue 7 and visit, and then the first element of the dequeue 7 and visit, traverse carry out. At this time, the value of all vertices in the array is 1.

Code

bool visited[MAX_TREE_SIZE] 
void BFSTraverse(Graph G){
    
      
    for(int i=0; i<G.vexnum;i++){
    
    
        visited[i]=FALSE;
    }
    InitQueue(Q);
    //for循环的作用,我们上面讲的是一个连通图,所有顶点都可以通过一个顶点依次进行访问
    //但是如果一个图不是连通的,我们需要遍历所有顶点
    for(int i=0;i<G.vexnum;i++){
    
    
        if(!visited(i)){
    
    
            BFS(G,i);
        }
    }
}
//广度优先搜索
void BFS(Graph G,int V){
    
    
    visit(v); //访问
    visited=TRUE; //TRUE 入队了,FALSE未入队
    EnQueue(Q,v); //将结点入队
    while(!isEmpty(Q)){
    
     //判断队列是否是空
        DeQueue(Q,v); //出队队首元素,并赋值到v中
        //FirstNeighbor 求图G中顶点x的第一个邻接顶点,存在返回顶点号,不存在返-1
        //判断 w是否大于0,如果是-1则说明没有邻接顶点了
        //NextNeighbor 求图G中顶点v的的下一个邻接顶点并赋值给w
        for(int w=FirstNeighbor(G,v);w>0;w=NextNeighbor(G,v,w)){
    
     
            if(!visited[w]){
    
    //判断是否入队过
                visit[w];
                visited[w]=TRUE;
                EnQueue(Q,w);
            }
        }
    }
}

3. Application

3.1 Single source shortest path problem with unauthorised graph

Define the shortest path d(u,v) from vertex u to vertex v as any path 最少的边数from u to v. If there is no path from u to v, then d(u,v)=∞ (the table is not reachable)

//和广度优先搜索相似,增加了保存最短路径的一个数组
void BFS_MIN_Distance(Graph G,int u){
    
    //传入图 和 初始顶点
    for(int i=0;i<G.vexnum;++i){
    
     // 
        d[i]=MAX; //保存最短路径的值,我们初始化为最大值
    }
    visited[u]=TRUE;//标识为该顶点已经入队
    d[u]=0;//初始顶点路径值改为0
    EnQueue(Q,u);//入队
    while(!isEmpty(Q)){
    
    //判断队列时候为空
    	DeQueue(Q,u);//出队队首元素
        //FirstNeighbor 求图G中顶点x的第一个邻接顶点,存在返回顶点号,不存在返-1
        //判断 w是否大于0,如果是-1则说明没有邻接顶点了
        //NextNeighbor 求图G中顶点v的的下一个邻接顶点并赋值给w
        for(int w=FirstNeighbor(G,u);w>0;w=NextNeighbor(G,u,w)){
    
    
            if(!visit[w]){
    
    //判断该顶点是否已经被访问过
                visited[w]=TRUE;//设置被访问过
                //d[u]表示到初始顶点的最短路径,w是它的邻接点,所以+1等目前w到初始顶点的最短路径
                d[w]=d[u]+1;
                EnQueue(Q,w);//入队
            }
        } 
    }
}

3.2 Breadth First Spanning Tree

Breadth-first spanning tree : In the breadth traversal process, we can get a traversal tree, called breadth-first spanning tree (spanning forest)

If it is a connected graph we will get a spanning tree, and if it is a non-connected graph we will get a spanning forest

连通图: Any two nodes are connected

The breadth-first spanning tree of the adjacency matrix method is unique, and the adjacency list method is not unique

Because the adjacency matrix representation of a graph is unique, the process of our traversal is also unique, but the order of our input in the adjacency list representation is not unique. The generated edge table is not unique, and the corresponding traversal process (traversing the edge Order) is not unique anymore

4. Depth First Search (DFS)

Breadth-first search is similar to tree-level traversal, while depth-first search is similar to tree-level traversal. If such a tree is regarded as a graph, its pre-order traversal order is the depth-first search traversal order of the graph.

We can find that the breadth-first search is traversed according to the width of the graph, and the depth-first search is searched and traversed according to the depth of a path

Depth First Search (DFS)

  • First visit the starting vertex v
  • Then start from v to visit 任意an adjacent and 未被访问adjacent vertex Wi of v
  • Then visit 未被访问any vertex Yi adjacent to Wi
  • If Wi has no adjacent and unvisited vertices, return to its previous vertex v
  • Repeat the above process until all vertices are visited

We traverse the above figure through the above algorithm idea: first visit 1, then we can visit any vertex 2 or 3, we visit 2, then we can visit any vertex 4 or 5, we visit 4, and then we can visit any vertex 7 Or 5 (7 and 5 are also adjacent vertices of 4), suppose we visit 5, then 5 has no adjacent and unvisited vertices, we return to 4, then visit vertex 7, then return to vertex 1, then visit vertex 3, then Visit 6, the traversal is complete:1 2 4 5 7 3 6

From the above traversal process, we can find that the entire process can be used 递归to achieve, of course, recursion can also be converted to achieve, and we also need an auxiliary marker array. Namely: recursion (stack) + auxiliary tag array

Code

bool visited[MAX_TREE_SIZE]//辅助标记数组
void DFSTraverse(Graph G){
    
    
    for(int i=0;i<G.vexnum;i++){
    
    
        visited[i]=FALSE;//初始化所有结点都未必访问
    }
    for(int i=0;i<G.vexnum;i++){
    
    
        if(!visited[i]){
    
    //如果结点未被访问
            DFS(G,i);//G:图,i:起始顶点的编号
        }
    }
}
void DFS(Graph G,int v){
    
    
    visit(v); //访问
    visited[v]=TRUE;//置为访问过
    for(int w=FirstNeighbor(G,v);w>0;w=NextNeighbor(G,v,w)){
    
    
            if(!visit[w]){
    
    //判断该顶点是否已经被访问过
                DFS(G,w);//递归
            }
    }
}

As shown in the above figure, we traverse through the above code: starting from A, visit A ​​and set the auxiliary tag array value corresponding to A to TREUE, then we find the first adjacent vertex of A, such as C, and then we judge that C is not Visited, then continue to call the DFSfunction, visit C, similarly continue to find the first adjacent vertex D of C, judge that D has not been visited, we visit vertex D, and then D has no adjacent vertex. This function ends, and we return to visit C In the DFSfor loop of the vertex of C, find the second adjacent point E of C, and judge that E has not been asked by the party. We visit E, then E has no adjacent vertices, and continue to return to C, C has no unvisited adjacent vertices , We return to DFSthe for loop of A and find that the second adjacent vertex E of A has been visited, so A has no unvisited adjacent vertices. We return to the DFSTraversesecond for loop of the function. The loop judges that B finds that B is visited, then calls the DFSfunction, visits D, sets it TRUE, and then finds that B does not have unvisited adjacent vertices, so it returns to DFSTraversethe second for loop of the function and finds that there is no unvisited The vertices of, so the traversal ends:ACDEB

From this process, we can see that the function of the first function is that if our initial vertex cannot traverse all the vertices in the graph, we can loop through each vertex.

The DFS (BFS) sequence of the adjacency matrix method is unique, and the adjacency list method is not unique

5. Depth first spanning tree

Depth-first spanning tree : In the process of depth traversal, we can get a traversal tree, called depth-first spanning tree (spanning forest)

The depth-first spanning tree of the adjacency matrix method is unique, and the adjacency list method is not unique

6. Traversal and connectivity issues

How to judge the connectivity of the graph through traversal?

The above is an undirected graph: whether we use BFS or DFS, we can access other vertices through any vertex, so it is a connected graph

So we have the following conclusion: In an undirected graph, a traversal (calling BFS or DFS once) is performed at any node division. If all nodes can be visited, the graph is connected.

The above is a disconnected undirected graph. When we traverse (BFS or DFS), in order to traverse to each vertex, we need a for loop to call BFS or DFS for each vertex.

From this we can get the following conclusion: In an undirected graph, the number of times the traversal function (BFS or DFS) is called is the number of connected components

For example, the above is a directed graph: we can traverse to any vertex in DFS starting from vertex B, but can access to all vertices mean that the graph is a strongly connected graph? The answer is of course no. Being able to traverse all vertices only means that there is a directed assault from one vertex to another.

If we traverse from vertex A in the above figure, we need to call DFS twice, so in a directed graph, the number of calls to the traversal function (BFS or DFS) is not the number of strongly connected components

Undirected graphs are called connected graphs, and directed graphs are called strongly connected

7. Rimuke

Knowledge about data structure, the official account is being updated simultaneously, welcome to follow

Guess you like

Origin blog.csdn.net/qq_41941875/article/details/106817283