图的遍历

图的遍历

一,简介:

图的遍历主要就是深度和广度优先遍历。下面引入一个图:

图的遍历 

 

 

  其实不难发现这个图是有两个部分组成,分别是每一个节点以及节点之间的连接。现在要遍历这个图其实就是按照编号来进行遍历,把这个图的每一个顶点遍历一遍。每一个顶点是第几个被访问到的叫做时间戳。

下面是这个遍历的过程:

  首先从1出发,发现2号顶点还没有走过1于是现在到了2号顶点,从2号顶点在开始,发现四号顶点没有走过,所以现在就走到四号顶点,在四号顶点发现没有没有走过的顶点了,所以现在要返回到2,在2发现还是老样子,没有可以去的地方,所以现在就再返回1,在1这个位置发现3没有走过,所以现在到了3这个位置,再从3到5.现在所有的顶点全部都走完了!!

二,图如何储存的呢?

      关于图的储存这里介绍一种简单的方法:邻接矩阵存储法,这个方法说白了就是用二维数组来储存这个图。看下图:

                                                                   图的遍历

 

下面就来解释一下这个图吧:第一行也就是代表着第一个节点:对于第一个节点所相连的节点标记为1,看第一行,也就是1号节点和2,3,5有相连,主对角线是0是因为一个节点不能和它本身相连,没有相连的就是无穷,但是这个无穷不好表示所以就暂时用99999999来表示吧。这里还有一个细节,图分为2个类,有向图和无向图。其实从这个图里可以发现无向图矩阵是对称阵。但是如果是有向图的话,就只有在主对角线一边有路。

 

三,代码实现;

#include <stdio.h>
int book[101] = { 0 };
int e[101][101];
int sum = 0, n;
void dfs(int cur) {//cur就是当前的编号
    int i;
    printf("%d", cur);
    if (sum == n) {//所有顶点已经访问了
        return;//这个退出条件真的要认真思考
    }
    for (int i = 1; i <= n; i++) {//从一号到n号依次尝试,看每一个顶点是否有边相连。
        if (e[cur][i] == 1 && book[101] == 0) {//cur就是现在遍历到的节点
            book[i] = 1;//book用来记录图是否已经遍历完了
            dfs(i);//从顶点i再开始出发                                            
        }
    }
    return;
}
int main() {
    int i, j, a, m, b;
    scanf_s("%d %d", &n, &m);
    for ( i = 1; i <= n; i++) {
        for ( j = 1; i <= m; j++) {
            if (i == j) {
                e[i][j] = 0;
            }
            else {
                e[i][j] = 9999;
            }
        }
    }
    //继续读入顶点的边
    for ( i = 1; i <= m; i++) {
        scanf_s("%d %d", &a, &b);
        e[a][b] = 1;
        e[b][a] = 1;//这个图是无向图,所以这个是双向的
    }
    book[1] = 1;
    dfs(1);
    return 0;

 

这里就是有深度优先搜索来进行搜索(这里不说太多),这里补充解释一下深度优先搜索的核心代码吧:

//后面其实就是深度优先搜索的核心代码
void dfs(int step) {
    //判断边界
    //尝试每一种可能
    for (int i = 1; i <= n; i++) {
        //继续下一步
        dfs(step + 1);
        后续操作
    }
    //返回
}

后面是广度优先搜索:

#include <stdio.h>
int main() {
    int i, j, n, m, a, b, cur, book[101] = { 0 }, e[101][101];
    int que[10001], head, tail;
    scanf_s("%d %d", &m, &n);
    for (i = 1; i <= n; i++) {
        for (j = 1; j <= n; j++) {
            if (i == j) {
                e[i][j] = 0;
            }
            else {
                e[i][j] = 999999999;
            }
        }
    }
    //读入顶点之间的边
    for (i = 1; i <= m; i++) {
        scanf_s("%d %d", &a, &b);
        e[a][b] = 1;
        e[b][a] = 1;
    }
    //后面开始深度搜索,现在其实也是做一个复习把
    head = 1;
    tail = 1;
    //从一号顶点出发,说明一号顶点已经访问了
    que[tail] = 1;
    tail++;
    book[1] = 1;
    //后面还是老样子当队列不为空的时候来进行循环
    while (head < tail && tail <= n) {//数字储存不能超过一行的内容,这里好好思考一下
        cur = que[head];//从当前的编号开始向外拓展
        for (i = 1; i <= n; i++) {
            //判断从顶点cur到i是否有边,并判断顶点i是否已经访问过了
            if (e[cur][i] == 1 && book[i] == 0) {
                book[i] = 1;
                //现在把上一个图相连的这个点入队
                que[tail] = i;
                tail++;
            }
            if (tail > n) {

                break;//第一行结束这个循环就break掉
            }
        }
        head++;//注意现在这个head就轮到下一个图了,比如2,也就是说现在已经到了第二行了。
    }
    for (i = 1; i < tail; i++)
        printf("%d", que[i]);
    return 0;
}

 图的遍历其实只是一个基础,本来想先想写深度优先搜索和广度优先搜索的,但是想写的太多了,正好最近在看最短路径的问题,所以就先写了比较基础的图的遍历。 

 

 

 

 

 

 

 

 

 

 

 

  

 

上一篇:C#|lambda 表达式精简过程


下一篇:例题:输出101-200质数(超详细解析)