图|图的遍历及应用

图的遍历及其应用

一、图的深度遍历及其应用

1. 图的深度遍历(Depth-First Search)

1)基本思想:递归
(1)访问顶点A;
(2)从A的未被访问的邻接点中选取一个顶点w,从w出发进行深度优先遍历;
(3)重复上面两步,直至所有顶点均被访问过。
2)辅助数组:
visited[ ]:用来记录每个顶点是否被访问过。1,访问过;0,未访问过。
3)算法实现:

//邻接矩阵的深度优先遍历
void DFS(MGraph &G, int v, int visited[]) {
    int i;
    printf("%c\n", G.vexs[v]);
    visited[v] = 1;
    for(i=0; i<G.vexNum; i++) {
        if (G.arcs[v][i] != 0 && G.arcs[v][i] != INFINITY && !visited[i]) {
            DFS(G, i, visited);
        }
    }
}
//邻接表的深度优先遍历
void DFS(ALGraph &G, int v, int visited[]) {
    ArcNode *p = G.adjList[v].firstArc;
    printf("%c\t", G.adjList[v].vertex);
    visited[v] = 1;
    while (p) {
        if (!visited[p->adjvex]) {
            DFS(G, p->adjvex, visited);
        }
        p = p->next;
    }
}

2.图的深度遍历的应用

1)求一条包含所有顶点的回路(Hamilton)
  • 【分析】此为汉密尔顿(Hamilton)问题。起点的选择顶点的邻接顺序会影响该简单路径是否能被找到;
  • 修改DFS算法:访问顶点时将该顶点序号加入数组path[ ],n++判断是否所有顶点已被访问;某顶点所有邻接点全部被访问后回溯,计数器n–;
  • 算法实现:
void DFS(MGraph &G, int i, int path[], int visited[], int &n) {
    int j;
    visited[i]=1;
    path[n]=i;
    n++;
    if (n==G.vexNum) {      // 符合条件输出路径
        for (j=0; j<G.vexNum; j++) {
            printf("%d", path[j]);
        }
        putchar('\n');
        //return;
    }
    
    for (j=0; j<G.vexNum; j++) {
        if (G.arcs[i][j]==1 && !visited[j]) {
            DFS(G, j, path, visited, n);
        }
    }
    visited[i] = 0;
    n--;
}

void Hamilton(MGraph G) {
    int i, n=0;     //n记录当前该路径上的顶点数
    int path[G.vexNum];
    int visited[G.vexNum];
    
    for (i=0; i<G.vexNum; i++) {
        visited[i] = 0;
    }
    for (i=0; i<G.vexNum; i++) {
        path[i] = INFINITY;
    }
    for (i=0; i<G.vexNum; i++) {
        if (!visited[i]) {
            DFS(G, i, path, visited, n);        //i为起始点,n为加入路径的顶点个数
        }
    }
}
2)判断图中是否存在环
  • 【分析】在图的深度遍历过程中,若出现与某个顶点有邻接关系的所有顶点均被访问过,则一定出现了回路。
  • 修改DFS算法:对顶点x做深度优先遍历时,先计算其度dx和与它有邻接关系的访问标志数v;若dx==v,则出现回路,否则继续。
  • 算法实现:
 int DFS(MGraph &G, int i, int visited[]) {
    int j, vi, di;
    visited[i] = 1;
    for (di = 0, vi = 0, j = 0; j<G.vexNum; j++) {
        if (G.arcs[i][j]==1) {
            di++;
            if (visited[j]) {
                vi++;
            }
        }
    }
    if (di == vi && di!=1) {
        printf("有回路!\n");
        return 1;
    }
    for (j=0; j<G.vexNum; j++) {
        if (G.arcs[i][j]==1 && !visited[j]) {
            if (DFS(G, j, visited)) {
                return 1;
            } else {
                return 0;
            }
        }
    }
    printf("无回路!\n");
    return 0;
}
3)求无向图的顶点a到i之间的简单路径
  • 【分析】深度遍历过程中将所有访问到的顶点下标计入数组path[ ],若找到i顶点,则path中存储的即为a到i的简单路径;若未找到,删除path[ ]中的一个下标,回退,直至找到i。
  • 算法实现:
//辅助函数:加入Path[]数组和从path[]中删除
void Append(int path[], int i);
void Delete(int path[]);
void DFSearchPath(MGraph G, int v, int w, int path[], int visited[], int &found) {
    int j;
    Append(path, v);
    visited[v] = 1;
    for (j=0; j<G.vexNum && !found; j++) {
        if (G.arcs[v][j]==1 && !visited[j]) {
            if (j == w) {
                found=1;
                Append(path, j);
            }
            DFSearchPath(G, j, w, path, visited, found);
        }
    }
    if (!found) {
        Delete(path);
    }
}

二、图的广度遍历及其应用

1. 图的广度遍历(Breadth-First Search)

1)基本思想:
(1)访问初始顶点A,并将其顶点序号入队;
(2)队列不空,则出队;依次访问它的每一个未被访问过的邻接点,并将其编号入队;
(3)重复(2)直至队列空,遍历结束。
【例】:
《图|图的遍历及应用》
《图|图的遍历及应用》
2)代码实现:

队列的操作:

typedef struct {
    int front, reer;
    int data[MAXSIZE];
} Queue;

void initQueue(Queue &Q) {
    Q.front = Q.reer = 0;
    for(int i=0; i<MAXSIZE; i++) {
        Q.data[i] = INFINITY;
    }
}

void enterQueue(Queue &Q, int v) {
    if((Q.front+1)%MAXSIZE == Q.reer) {
        printf("Queue full\n");
        return;
    }
    Q.data[Q.front] = v;
    Q.front = (++Q.front)%MAXSIZE;
}

int deletQueue(Queue &Q) {
    int i = Q.data[Q.reer];
    Q.data[Q.reer] = INFINITY;
    Q.reer = (++Q.reer)%MAXSIZE;
    return i;
}

int emptyQueue(Queue Q) {
    if(Q.front == Q.reer) {
        return 0;
    }
    return 1;
}

算法实现:

//邻接矩阵的广度优先遍历
void BFS(MGraph G, Queue &Q, int v, int visited[]) {
    int a, i = 0;
    enterQueue(Q, v);
    while(emptyQueue(Q)) {
        a = deletQueue(Q);
        visited[a] = 1;
        printf("%c\t", G.vexs[a]);
        i=0;
        while(i<G.vexNum) {
            if(G.arcs[a][i] == 1) {
                if(visited[i]==0) {
                    enterQueue(Q, i);
                    visited[i] = 1;
                }
            }
            i++;
        }
    }
}
//邻接表的广度优先遍历
void BFS(ALGraph G, Queue &Q, int v, int visited[]) {
    int a;
    ArcNode *p=NULL;
    initQueue(Q);
    enterQueue(Q, v);
    
    visited[v] = 1;
    while (emptyQueue(Q)) {
        a = deletQueue(Q);
        printf("%c\t", G.adjList[a].vertex);
        p = G.adjList[a].firstArc;
        while (p) {
            if(!visited[p->adjvex]) {
                enterQueue(Q, p->adjvex);
                visited[p->adjvex] = 1;
            }
            p = p->next;
        }
    }
}

2. 图的广度遍历的应用

求无向图的顶点A、B之间的最短路径
【分析】从源点进行BFS,让进入队列的节点既能完成按层遍历,又能记住路径;将队列节点修改为带prior指针指向该节点前驱;
对队列的操作修改:

typedef struct node{
    int data;
    struct node *prior, *next;
}QNode;

typedef struct {
    QNode *fron, *reer;
}Queue;

void initQueue(Queue &Q) {
    Q.fron = Q.reer = new QNode;
    Q.fron->prior = Q.fron->next = NULL;
}

void enterQueue(Queue &Q, int data) {
    Q.reer->next = new QNode;
    Q.reer = Q.reer->next;
    Q.reer->data = data;
    Q.reer->next = NULL;
    Q.reer->prior = NULL;
}

void deleQueue(Queue &Q) {
    Q.fron = Q.fron->next;
}

算法实现:

void BFSearch(MGraph G, Queue &Q, int vi, int vj, int visited[]) {
    int a, i;
    enterQueue(Q, vi);
    visited[vi] = 1;
    while (Q.fron != Q.reer) {
        a = Q.fron->next->data;
        deleQueue(Q);
        for (i=0; i<G.vexNum; i++) {
            if (G.arcs[a][i] == 1 && visited[i]==0) {
                enterQueue(Q, i);
                Q.reer->prior = Q.fron;
                visited[i] = 1;
                if (i==vj) {
                    return;
                }
            }
        }
    }
}

void creatGraph(MGraph &G) {
    int i, j, from, to;
    
    //initial Graph
    for(i=0; i<MAXSIZE; i++) {
        for(j=0; j<MAXSIZE; j++) {
            if(i == j) {
                G.arcs[i][j] = 0;
                continue;
            }
            G.arcs[i][j] = INFINITY;
        }
    }
    printf("Please input verNum & arcNum\n");
    scanf("%d%d", &G.vexNum, &G.arcNum);
    
    printf("Please input vertices' name\n");
    getchar();
    for(i=0; i<G.vexNum; i++) {
        scanf("%c", &G.vexs[i]);
    }
    
    printf("Please input edge\n");
    for(i=0; i<G.arcNum; i++) {
        scanf("%d%d", &from, &to);
        G.arcs[from][to] = 1;
        G.arcs[to][from] = 1;
    }
}
    原文作者:数据结构之图
    原文地址: https://blog.csdn.net/qq_41594999/article/details/84669040
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞