数据结构与算法——图的遍历

422 阅读5分钟

1.深度优先搜索(简称“深搜”或DFS)

深度优先搜索的过程类似于树的先序遍历,首先从例子中体会深度优先搜索。

采用深度优先算法遍历上图的过程为:
1.首先任意找一个未被遍历过的顶点,例如从A开始,由于A率先访问过了,所以,需要标记A的状态为访问过;
2.然后遍历A的邻接点,例如访问B,并做标记,然后访问B的邻接点,例如C (做标记),然后D,然后F......
3.当继续遍历H的邻接点时,根据之前做的标记显示,所有邻接点都被访问过了。此时,从H回退到G,看G是否有未被访问过的邻接点,如果没有,继续回退到F, E,D......
4.回退到D时,找到未被访问的I, 继续查看I的临界点是否有未被访问的;

最后深度优先搜索获得的顶点的遍历次序为:
A -> B -> C -> D -> E -> F -> G -> H -> I

所谓深度优先搜索,是从图中的一个顶点出发,每次遍历当前访问顶点的临界点,一直到访问的顶点没有未被访问过的临界点为止。然后采用依次回退的方式,查看来的路上每一个顶点是否有其它未被访问的临界点。访问完成后,判断图中的顶点是否已经全部遍历完成,如果没有,以未访问的顶点为起始点,重复上述过程。

1.1邻接矩阵的深度优先遍历

  1. 将图的顶点和边信息输入到图结构中;
  2. 创建⼀个visited 数组,⽤来标识顶点是否已经被遍历过.
  3. 初始化visited 数组,将数组中元素置为FALSE
  4. 选择顶点开始遍历.(注意非连通图的情况)
  5. 进⼊递归; 打印i 对应的顶点信息. 并将该顶点标识为已遍历.
  6. 循环遍历边表,判断当前arc[i][j] 是否等于1,并且当前该顶点没有被遍历过,则继续递归 DFS;
Boolean visited[MAXVEX]; /* 访问标志的数组 */
void DFS(MGraph G, int i){
    //3.顶点i置为已访问 并打印
    visited[i] = TRUE;
    printf("%c", G.vexs[i]);
    
    //4.循环遍历边表
    for (int j=0; j<G.numVertexes; j++) {
        //判断arc[i][j]是否等于1 并且该顶点没有被访问过 继续递归遍历
        if (G.arc[i][j] == 1 && !visited[j]) {
            DFS(G, j);
        }
    }
}

void DFSTravese(MGraph G){
    //1.初始化visited数组
    for (int i = 0; i<G.numVertexes; i++) {
        visited[i] = FALSE;
    }
    
    //2.选择顶点开始遍历
    for (int i=0; i<G.numVertexes; i++) {
        if (!visited[i]) {
            DFS(G, i);
        }
    }
}

1.2邻接表的深度优先遍历

  1. 利利⽤用邻接矩阵将信息存储到邻接表中
  2. 创建⼀一个visited 数组,⽤用来标识顶点是否已经被遍历过.
  3. 初始化visited 数组,将数组中元素置为FALSE
  4. 选择顶点开始遍历.(注意⾮非连通图的情况)
  5. 进⼊入递归; 打印i 对应的顶点信息. 并将该顶点标识为已遍历.
  6. 循环遍历边表,判断当前顶点 是否等于1,并且当前该顶点没有被遍历过,则继续递归 DFS;
//1.创建⼀个visited 数组,⽤来标识顶点是否已经被遍历过.
Boolean visited[MAXSIZE];

/* 邻接表的深度优先递归算法 */
void DFS(GraphAdjList GL, int i){
    EdgeNode *p;
    
    //4.打印i顶点的信息 并将改顶点标记为已遍历
    printf("%c ", GL->adjList[i].data);
    visited[i] = TRUE;
    
    p = GL->adjList[i].firstedge;
    while (p) {
        if (!visited[p->adjvex]) {
            DFS(GL, p->adjvex);
        }
        p = p->next;
    }
    
}

/* 邻接表的深度遍历操作 */
void DFSTraverse(GraphAdjList GL){
    for (int i=0; i<GL->numVertexes; i++) {
        //2. 将访问记录数组默认置为FALSE
        visited[i] = FALSE;
    }
    
    //3. 选择一个顶点开始DFS遍历.
    for (int i=0; i<GL->numVertexes; i++) {
        if (!visited[i]) {
            DFS(GL, i);
        }
    }
}

2.广度优先搜索(BFS)

广度优先搜索类似于树的层次遍历。从图中的某一顶点出发,遍历每一个顶点时,依次遍历其所有的邻接点,然后再从这些邻接点出发,同样依次访问它们的邻接点。按照此过程,直到图中所有被访问过的顶点的邻接点都被访问到。

最后还需要做的操作就是查看图中是否存在尚未被访问的顶点,若有,则以该顶点为起始点,重复上述遍历的过程。

广度优先搜索的实现需要借助队列这一特殊数据结构.

过程如下: 1.顶点A入栈,标记
2.将A出栈,A未被标记的邻接点BF(并标记)入栈
3.B出栈,B的未被标记的邻接点IG(并标记)入栈
4.F出栈,邻接点E入栈
5.C出栈,D入栈
6.I出栈,I没有未被标记的邻接点
7.G出栈,H入栈
8.E出栈
9.D出栈
10.H出栈,此时已全部标记完成。

遍历顶点的顺序为:
A -> B -> F -> C -> I -> G -> E -> D -> H

2.1 邻接矩阵的广度优先遍历

/*邻接矩阵广度优先遍历-代码实现*/
//访问标志数组
Boolean visited[MAXSIZE];
void BFSTraverse(MGraph G){
    
    //初始化队列
    Queue Q;
    InitQueue(&Q);
    
    //将访问记录数组默认置为FALSE
    for (int i=0; i<G.numVertexes; i++) {
        visited[i] = FALSE;
    }
    
    //遍历邻接表中的每一个顶点(对于连通图只会执行1次,这个循环是针对非连通图)
    for (int i=0; i<G.numVertexes; i++) {
        if (!visited[i]) {
            visited[i] = TRUE;
            printf("%c  ",G.vexs[i]);
            
            //下标入队
            EnQueue(&Q, i);
            int k;
            while (!QueueEmpty(Q)) {
                DeQueue(&Q, &k);
                for (int j=0; j<G.numVertexes; j++) {
                    if (G.arc[k][j] == 1 && !visited[j]) {
                        visited[j] = TRUE;
                        printf("%c  ",G.vexs[j]);
                        EnQueue(&Q, j);
                    }
                }
            }
        }
    }
}

2.2 邻接表的广度优先遍历

/*邻接表广度优先遍历*/
Boolean visited[MAXSIZE]; /* 访问标志的数组 */
void BFSTraverse(GraphAdjList GL){
    
    EdgeNode *p;
    
    Queue Q;
    InitQueue(&Q);
    
    for (int i=0; i<GL->numVertexes; i++) {
        visited[i] = FALSE;
    }
    
    int k;
    for (int i=0; i<GL->numVertexes; i++) {
        if (!visited[i]) {
            
            EnQueue(&Q, i);
            visited[i] = TRUE;
            printf("%c ",GL->adjList[i].data);
            
            while (!QueueEmpty(Q)) {
                DeQueue(&Q, &k);
                p = GL->adjList[k].firstedge;
                while (p) {
                    if (!visited[p->adjvex]) {
                        EnQueue(&Q, p->adjvex);
                        visited[p->adjvex] = TRUE;
                        printf("%c ",GL->adjList[p->adjvex].data);
                    }
                    p = p->next;
                }
            }
        }
    }
}