因此,我需要对给定的图进行深度优先搜索遍历,然而,如果图中的一个 node 有多个相邻的邻居,我需要 Select 值最低的 node .因此,我实现了以下递归深度优先搜索函数:

void DFS(struct Graph *graph, int vertex) {
    struct node *adjList = graph->adjLists[vertex];
    struct node *temp = adjList;

    graph->visited[vertex] = 1;
    printf("Visited %d \n", vertex);
  
    int neighbouring_nodes[graph->numVertices];
  
    while (temp != NULL) {
        int count = 0;
        struct node *temp_cpy = temp;
     
        while (temp_cpy != NULL) {
            neighbouring_nodes[count] = temp_cpy->vertex;
            count++;
            temp_cpy = temp_cpy->next;
        }

        int smallest_node = neighbouring_nodes[0];
        
        for (int i = 0; i < count; i++) {
            if (neighbouring_nodes[i] < smallest_node) {
                smallest_node = neighbouring_nodes[i];
            }
        }
    
        if (graph->visited[smallest_node] == 0) {
            DFS(graph, smallest_node);
        } else if (graph->visited[smallest_node] == 1 && count == 1) {
            //if the node is visited but is it the only neighbour
            DFS(graph, smallest_node);
        }
        temp = temp->next;
    }
}

但当我运行程序时,它会导致无限循环.我想我知道为什么我得到了一个无限循环,可能是因为从来没有返回条件,所以递归函数一直在运行?

这种深度优先搜索是否可以使用递归函数?如果是,我错在哪里?如果没有,我将如何迭代?

下面是我没有DFS功能的完整程序:

// DFS algorithm in C

#include <stdio.h>
#include <stdlib.h>

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

struct node *createNode(int v);

struct Graph {
    int numVertices;
    int *visited;
    struct node **adjLists;
};

// Create a node
struct node *createNode(int v) {
    struct node *newNode = malloc(sizeof(struct node));
    newNode->vertex = v;
    newNode->next = NULL;
    return newNode;
}

// Create graph
struct Graph *createGraph(int vertices) {
    struct Graph *graph = malloc(sizeof(struct Graph));
    graph->numVertices = vertices;

    graph->adjLists = malloc(vertices * sizeof(struct node*));

    graph->visited = malloc(vertices * sizeof(int));

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

// Add edge
void addEdge(struct Graph *graph, int src, int dest) {
    // Add edge from src to dest
    struct node *newNode = createNode(dest);
    newNode->next = graph->adjLists[src];
    graph->adjLists[src] = newNode;

    // Add edge from dest to src
    newNode = createNode(src);
    newNode->next = graph->adjLists[dest];
    graph->adjLists[dest] = newNode;
}

// Print the graph
void printGraph(struct Graph *graph) {
    int v;
    for (v = 0; v < graph->numVertices; v++) {
        struct node *temp = graph->adjLists[v];
        printf("\n Adjacency list of vertex %d\n ", v);
        while (temp) {
            printf("%d -> ", temp->vertex);
            temp = temp->next;
        }
        printf("\n");
    }
}

int main() {
    struct Graph *graph = createGraph(4);
    addEdge(graph, 0, 1);
    addEdge(graph, 0, 2);
    addEdge(graph, 1, 2);
    addEdge(graph, 2, 3);

    printGraph(graph);

    DFS(graph, 2);

    return 0;
}

推荐答案

以下是我的 idea :

void DFS(struct Graph* graph, int vertex) {
    struct node* temp = graph->adjLists[vertex];

    graph->visited[vertex] = 1;
    printf("Visited %d \n", vertex);

    int neighbouring_nodes[graph->numVertices];

    int count = 0;

    while(temp != NULL) {
        neighbouring_nodes[count] = temp->vertex;
        count++;
        temp = temp->next;
    }

    int smallest_node = neighbouring_nodes[0];
    
    //   Need to search (at most) in every neighbouring node
    for (int i = 0; i < count; i++) {
        //   Go through all nodes in neighbouring_nodes array in order
        //   to find the smallest unvisited one, if it exists
        for (int j = 0; j < count; j++){
            //   if current smallest_node has already been visited and
            //   neighbouring_nodes[j] is unvisited, assign it to smallest_node
            if (graph->visited[smallest_node] == 1 && graph->visited[neighbouring_nodes[j]] == 0){
                    smallest_node = neighbouring_nodes[j];
            }
            //   if neighbouring_nodes[j] is smaller than smallest_node,
            //   assign it to smallest_node
            if (graph->visited[neighbouring_nodes[j]] == 0 && neighbouring_nodes[j] < smallest_node){
                smallest_node = neighbouring_nodes[j];
            }
        }
        if (graph->visited[smallest_node] == 0){
            //   calls DFS on the smallest unvisited neighboring node, if it exists
            DFS(graph, smallest_node);
        }else{
            //   otherwise (all neighboring nodes already visited)
            //   return control to the caller function
            return;
        }
    }
}

我不能百分之百肯定我理解你想用while (temp != NULL)while (temp_cpy != NULL)个循环做什么,但我真的想不出使用这种方法的方法,尤其是在你想按升序访问相邻 node 的特殊情况下.

让我们假设一个简单的图,如6->0->1,调用DFS(g, 0)将得到temp指向6->1->NULL(也可以是1->6->NULL,取决于您如何构建图),然后smallest_node将是1,因此将访问 node 1,temp = temp->next将"分配"1->NULLtemp.回到循环的开始,现在temp_cpy将"等于"temp,因此是1->NULL.即使 node 6没有被访问,它也不再在列表上,另一方面,已经被访问的 node 1仍然存在.此外,count现在等于1,因此满足条件(graph->visited[smallest_node] == 1 && count == 1)并调用DFS(g, 1),这不应该,因为 node 1已经被访问.无限循环由此产生,因为当temp剩下一个(已访问)元素([some value]->NULL)时,总是满足先前的条件.一旦到达该点,您总是调用DFS(g, [some value]),这将永远不会返回控制,因为在到达temp = temp->next语句之前(应该将NULL分配给temp,从而结束while循环),DFS(g, [some other value])再次被调用,在某个点上,它将再次调用DFS(g, [some value]),以此类推.

如前所述,您的原始代码存在的一个问题是,您还为已访问的顶点调用了DFS函数,这种情况永远不会发生.当遇到已访问的相邻顶点时,您希望判断下一个顶点,或者如果没有未访问的相邻顶点,则将控制权交还给调用方函数.因此,最后一个if else语句不应该在那里.第二个问题是smallest_node Select 错误.这是因为temp_cpy(如上所述)的构造方式不一定包含所有未访问的相邻 node ,还因为您实际上正在查找该列表中的最小元素,无论它是否已被访问(同样是因为假设temp_cpy仅包含所有未访问的 node ).事实上,您应该寻找"最小的未访问 node ",而不是"最小的 node ".

在我的代码中,我用两个for循环遍历所有相邻 node ,找到最小的未访问 node 并调用DFS(g, [smallest unvisited node]),一旦没有未访问的邻居,return控制返回调用函数.

我希望这在某种程度上是可以理解的,我也希望我没有遗漏一些关于您对实现的 idea ,在这种情况下,我将非常感兴趣的一些解释!

这是DFS的一个简单版本,其中判断相邻 node ,并最终按照adjList中显示的顺序访问它们.在这种情况下,我认为while (temp != NULL)/temp = temp->next方法是有意义的:

void DFS(struct Graph *graph, int vertex) {
    struct node *temp = graph->adjLists[vertex];

    graph->visited[vertex] = 1;
    printf("Visited %d \n", vertex);

    //   for vertex search in every neighboring node
    while (temp != NULL) {
        //   if neighboring vertex temp->vertex not visited, then search there
        if (graph->visited[temp->vertex] == 0) {
            DFS(graph, temp->vertex);
        //   if already visited, go to the next vertex on the neighbors list
        }else{
            temp = temp->next;
        }
    }
    // when searched in all neighboring vertexes return control to caller
    return;
}

C++相关问答推荐

从STdin读写超过4096个字节

想了解 struct 指针和空指针转换

为什么这个C程序代码会产生以下结果?

C指针地址和转换

数据包未从DPDK端口传输到内核端口

如何在不使用其他数组或字符串的情况下交换字符串中的两个单词?

fwrite无法写入满(非常大)缓冲区

在 struct 中强制转换空指针

预先分配虚拟地址空间的区域

如何有效地编写代码来判断两个元素数量相同的数组即使在不同的位置也具有相同的元素?

S将C语言宏定义为自身的目的是什么?(在glibc标题中看到)

为什么此共享库没有预期的依赖项?

如何仅使用软件重新初始化STM32微控制器中的USB枚举?

合并对 struct 数组进行排序

发送和接收的消息中的Unix域套接字不匹配

传递给函数的 struct 中的数组

struct 中的qsort,但排序后的 struct 很乱

添加/删除链表中的第一个元素

快速准确计算double的小数指数

比 * 更快的乘法