📜  门| GATE-CS-2000 |问题22(1)

📅  最后修改于: 2023-12-03 15:28:41.089000             🧑  作者: Mango

门 | GATE-CS-2000 | 问题22

这道题目是GATE 2000年计算机科学考试的一道题目,属于数据结构和算法类别。下面是该题的详细题意:

题目描述

给定一个由n个结点和m条边组成的有向图。其中,表示顶点u到顶点v的边。 设从顶点1开始进行广度优先搜索(BFS)遍历,如果遍历到结点t,则停止遍历并输出1到t的最短路径。(输出的路径上包含的所有边组成的集合被称为最短路径。)

考虑设计和实现一个算法来解决这个问题。

为了实现该算法,我们需要使用以下类型的数据结构:

typedef struct node {
    int vertex;
    struct node *next;
}node;

typedef struct graph {
    int numVertices;
    node **adjLists;
}graph;

其中,graph表示一个有向图,numVertices表示图中结点的数目,adjLists是一个由链表构成的数组,adjLists[i]表示所有以结点i为起点的边所组成的链表。 node表示一个结点,vertex表示结点的编号,next存储下一个结点的指针。

请编写函数 shortestPath (graph *g, int startVertex, int targetVertex),其中, g是一个有向图,startVertex是广度优先搜索的起点,targetVertex是停止搜索的目标点。该函数应该返回从起点到目标点的最短路径。如果起点和目标点之间不存在路径,则返回一个空链表。

解题思路

该题考查的是广度优先搜索算法,具体思路如下:

  1. 创建一个队列Q,并将结点1入队,并将1的距离设置为0
  2. 取出队首的结点v,并将距离d设为v的距离
  3. 遍历v的所有邻居 w,对于每一个邻居w,设置其距离为d+1,并将w入队
  4. 重复上一步,直到队列为空或找到目标点t
  5. 如果找到了目标点t,则从 t开始,沿着每个结点的父结点指针回溯到起点,得到最短路径。
代码实现

下面是该题的代码实现,注释详尽,方便理解。代码片段如下,完整代码请见 github



// 创建一个新的结点
node *createNode(int v) {
    node *newNode = malloc(sizeof(node));
    newNode->vertex = v;
    newNode->next = NULL;
    return newNode;
}

// 创建一个有向图
graph *createGraph(int vertices) {
    graph *g = malloc(sizeof(graph));
    g->numVertices = vertices;

    // 创建邻接表
    g->adjLists = malloc(vertices * sizeof(node *));

    int i;
    for (i = 0; i < vertices; i++) {
        g->adjLists[i] = NULL;
    }

    return g;
}

// 添加边
void addEdge(graph *g, int src, int dest) {
    // 创建一个新的边
    node *newNode = createNode(dest);
    // 在链表头部插入新的结点
    newNode->next = g->adjLists[src];
    g->adjLists[src] = newNode;
}


// 释放内存
void freeGraph(graph *g) {
    if (g) {
        if (g->adjLists) {
            int v;
            for (v = 0; v < g->numVertices; v++) {
                if (g->adjLists[v]) {
                    free(g->adjLists[v]);
                }
            }
            free(g->adjLists);
        }
        free(g);
    }
}

// BFS搜索函数
node *BFS(graph *g, int startVertex, int targetVertex) {
    // 创建一个结构体数组用于跟踪已经访问过的结点及其父结点。
    struct queueItem {
        int vertex;         // 结点的编号
        int parentVertex;   // 该结点的父结点
    };

    // 创建一个队列,用于存储每个节点的编号
    queue *q = createQueue();

    // 初始化visited[]和parents[]数组
    int i;
    struct queueItem visited[g->numVertices];
    for (i = 0; i < g->numVertices; i++) {
        visited[i].vertex = false;
        visited[i].parentVertex = -1;
    }

    // 从起点开始,将其加入队列
    visited[startVertex].vertex = true;
    visited[startVertex].parentVertex = -1;
    enqueue(q, startVertex);

    // 执行 BFS,并在每个节点上跟踪其父结点
    while (!isEmpty(q)) {
        // 取出队首结点
        int currentVertex = dequeue(q);

        // 访问当前结点的所有邻居
        node *temp = g->adjLists[currentVertex];
        while (temp) {
            int adjVertex = temp->vertex;

            // 如果该结点未被访问过,将其加入队列,并将其父结点设置为当前结点
            if (!visited[adjVertex].vertex) {
                visited[adjVertex].vertex = true;
                visited[adjVertex].parentVertex = currentVertex;
                enqueue(q, adjVertex);
            }

            // 如果邻居节点是目标节点,我们就从目标节点开始回溯父结点指针直到起点
            if (adjVertex == targetVertex) {
                node *path = createNode(targetVertex);
                int parentVertex = visited[targetVertex].parentVertex;

                while (parentVertex != -1) {
                    node *newNode = createNode(parentVertex);
                    newNode->next = path;
                    path = newNode;
                    parentVertex = visited[parentVertex].parentVertex;
                }

                // 释放队列并返回路径
                freeQueue(q);
                return path;
            }

            // 继续遍历邻居节点
            temp = temp->next;
        }
    }

    // 释放队列,未找到目标点,返回空链表
    freeQueue(q);
    return createNode(-1);
}

// 寻找最短路径的函数
node *shortestPath(graph *g, int startVertex, int targetVertex) {
    return BFS(g, startVertex, targetVertex);
}

总结

该题考查的是图的广度优先搜索算法的应用。广度优先搜索是一种最基础的图搜索算法,用于寻找两个结点之间的最短路径。该算法的核心思想是从起点开始逐步向外扩展,直到找到目标结点为止。通过此题,我们可以更加深入地理解图的广度优先搜索算法,并掌握使用C语言实现该算法的技巧。