寻圈法编程用C语言实现

用C语言实现:面向查找并输出无向图中的一个圈,需要举例截图,要在VS能运行。

参考该博客修改:
https://blog.csdn.net/myRealization/article/details/107812221

img


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

// 定义邻接表中的边结构体
typedef struct Edge {
    int dest;  // 边的目标结点编号
    struct Edge* next;  // 指向下一个邻接边的指针
} Edge;

// 定义邻接表中的顶点结构体
typedef struct Vertex {
    int num;  // 顶点编号
    Edge* adj;  // 指向第一个邻接边的指针
} Vertex;

// 无向图邻接表
typedef struct Graph {
    int numVertexes;  // 顶点数
    Vertex* vertices;  // 指向顶点数组的指针
} Graph;

Graph* createGraph(int numVertexes) {
    Graph* graph = (Graph*)malloc(sizeof(Graph));
    graph->numVertexes = numVertexes;
    graph->vertices = (Vertex*)malloc(numVertexes * sizeof(Vertex));
    for (int i = 0; i < numVertexes; ++i) {
        graph->vertices[i].num = i;
        graph->vertices[i].adj = NULL;
    }
    return graph;
}

void destroyGraph(Graph* graph) {
    for (int i = 0; i < graph->numVertexes; ++i) {
        Edge* p = graph->vertices[i].adj;
        while (p != NULL) { // 遍历当前顶点的所有邻接边
            Edge* temp = p;
            p = p->next;
            free(temp);
        }
    }
    free(graph->vertices);
    free(graph);
}

void addEdge(Graph* graph, int v, int w) {
    if (v == w) return; // 不允许自环

    // 新建一条边,将其插入到顶点v的邻接表中
    Edge* newEdge1 = (Edge*)malloc(sizeof(Edge));
    newEdge1->dest = w;
    newEdge1->next = graph->vertices[v].adj;
    graph->vertices[v].adj = newEdge1;

    // 新建一条边,将其插入到顶点w的邻接表中
    Edge* newEdge2 = (Edge*)malloc(sizeof(Edge));
    newEdge2->dest = v;
    newEdge2->next = graph->vertices[w].adj;
    graph->vertices[w].adj = newEdge2;
}

// 递归算法, 使用visited[]和parent判断
// 顶点v可达的子图(连通分量)中是否存在环,如果存在则输出所有环
int isCyclicUtilDFS(Graph* graph, int v, int visited[], int parent[], int path[]) {
    visited[v] = 1; // 标记当前结点访问过
    // 对当前顶点的所有邻接点进行迭代
    for (Edge* e = graph->vertices[v].adj; e != NULL; e = e->next) {
        int i = e->dest;
        if (!visited[i]) { // 如果邻接点没有被访问过,递归访问
            parent[i] = v;      //记录父节点
            // 在 path 数组添加当前结点,表示我们正在访问这个结点
            path[i] = v;
            if (isCyclicUtilDFS(graph, i, visited, parent, path)) { // 发现存在环,返回1
                return 1; //及时退出
            }
        }
        else if (i != parent[v]) { // 被访问过,但不是当前结点v的父节点,说明存在环
            printf("Cycle found: ");
            // 输出环路路径
            for (int j = v; j != -1; j = parent[j]) {
                printf("%d -> ", j);
            }
            printf("%d\n", v);
            return 1; // 返回1
        }
    }

    return 0;
}

// 如果无向图中含有环,返回1,否则返回0
int isCyclicDFS(Graph* graph) {
    // 标记所有顶点为未访问
    int* visited = (int*)calloc(graph->numVertexes, sizeof(int));
    int* parent = (int*)calloc(graph->numVertexes, sizeof(int));
    int* path = (int*)calloc(graph->numVertexes, sizeof(int));
    for (int i = 0; i < graph->numVertexes; ++i) {
        visited[i] = 0;
        parent[i] = -1;
        path[i] = -1; // 初始状态,-1 表示不在路径中
    }

    // 对每个未访问过的顶点,调用isCyclicUtil判断环是否存在
    for (int u = 0; u < graph->numVertexes; ++u) {
        if (!visited[u]) { // 不对已经访问过的顶点进行递归
            path[u] = u;
            if (isCyclicUtilDFS(graph, u, visited, parent, path)) {
                free(visited);
                free(parent);
                free(path);
                return 1;
            }
        }
    }

    free(visited);
    free(parent);
    free(path);
    return 0;
}

int main() {
    int numVertexes, numEdges;
    printf("请键入顶点的数量: ");
    scanf("%d", &numVertexes);
    printf("请键入边的数量:");
    scanf("%d", &numEdges);

    Graph* g = createGraph(numVertexes);

    printf("请依次输入每条边的起点和终点顶点编号:\n");
    for (int i = 0; i < numEdges; ++i) {
        int v, w;
        scanf("%d%d", &v, &w);
        addEdge(g, v, w);
    }

    if (isCyclicDFS(g)) {
        printf("Contains Cycle!\n");
    }
    else {
        printf("Doesn't Contain Cycle!\n");
    }

    destroyGraph(g);
    return 0;
}

基于new bing部分指引作答:
运行截图:

img

以下是使用C语言编写的一个寻找并输出无向图中一个圈的示例代码。请注意,由于图的输入是动态的,这里使用了邻接矩阵表示图结构,并在代码中提供了一个示例输入矩阵。你可以根据需要修改输入矩阵。

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

#define MAX_VERTICES 100

// 邻接矩阵表示的图结构
typedef struct {
    int vertices[MAX_VERTICES][MAX_VERTICES];
    int numVertices;
} Graph;

// 初始化图
void initGraph(Graph *graph, int numVertices) {
    graph->numVertices = numVertices;
    int i, j;
    for (i = 0; i < numVertices; i++) {
        for (j = 0; j < numVertices; j++) {
            graph->vertices[i][j] = 0;
        }
    }
}

// 添加边
void addEdge(Graph *graph, int startVertex, int endVertex) {
    graph->vertices[startVertex][endVertex] = 1;
    graph->vertices[endVertex][startVertex] = 1;
}

// 深度优先搜索,寻找圈
int dfs(Graph *graph, int v, int visited[], int parent) {
    visited[v] = 1;
    int i;
    for (i = 0; i < graph->numVertices; i++) {
        if (graph->vertices[v][i]) {
            if (!visited[i]) {
                if (dfs(graph, i, visited, v)) {
                    return 1;
                }
            } else if (i != parent) {
                return 1;
            }
        }
    }
    return 0;
}

// 寻找并输出一个圈
void findCycle(Graph *graph) {
    int visited[MAX_VERTICES] = {0};
    int i;
    for (i = 0; i < graph->numVertices; i++) {
        if (!visited[i]) {
            if (dfs(graph, i, visited, -1)) {
                printf("Found a cycle in the graph!\n");
                return;
            }
        }
    }
    printf("No cycle found in the graph.\n");
}

int main() {
    // 创建一个无向图
    Graph graph;
    int numVertices = 5;
    initGraph(&graph, numVertices);

    // 添加边
    addEdge(&graph, 0, 1);
    addEdge(&graph, 1, 2);
    addEdge(&graph, 2, 3);
    addEdge(&graph, 3, 4);
    addEdge(&graph, 4, 0);

    // 查找并输出圈
    findCycle(&graph);

    return 0;
}

你可以将以上代码复制到Visual Studio(或其他C语言编译环境)中,然后进行编译和运行。这个示例代码创建了一个包含5个顶点的无向图,并添加了一些边。然后它使用深度优先搜索算法来查找并输出图中的一个圈。根据上述代码提供的输入边,此图中存在一个圈。如果在你的环境中成功运行,它应该会输出"Found a cycle in the graph!"。

以下是使用 C 语言实现寻圈法的代码示例,并通过 Visual Studio 运行:


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

#define MAX_VERTICES 1000

typedef struct {
    int data[MAX_VERTICES][MAX_VERTICES];
    int n;
} Graph;

bool is_cycle_exists(Graph* g, int u, int v) {
    for (int i = u + 1; i < g->n; i++) {
        if (g->data[u][i] && g->data[i][v]) {
            return true;
        }
    }
    return false;
}

void find_cycle(Graph* g) {
    int n = g->n;
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            if (is_cycle_exists(g, i, j)) {
                printf("Cycle found: ");
                for (int k = j; k != i; k = g->data[k][k == 0 ? n - 1 : k - 1]) {
                    printf("%d ", k);
                }
                printf("%d\n", j);
            }
        }
    }
}

int main() {
    Graph g = {{0, 1, 0, 0, 0},
               {1, 0, 1, 1, 0},
               {0, 1, 0, 1, 1},
               {0, 1, 1, 0, 1},
               {0, 0, 1, 1, 0}};
    g.n = 5;
    find_cycle(&g);
    return 0;
}

上述代码实现了一个简单的寻圈法,用于查找无向图中的圈。在代码中,使用一个结构体 Graph 表示无向图,其中 data 数组表示图中各个节点之间的边,n 表示节点数量。is_cycle_exists 函数用于判断是否存在从节点 u 到节点 v 的路径,find_cycle 函数用于查找图中是否存在环,并在控制台输出环的路径。在主函数中,定义了一个示例图 g,并调用 find_cycle 函数来查找环。


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


typedef struct link_list {
  int data;
  struct link_list *next;
}Data;

void print_list(Data *head) {
  while (head) {
    printf("%d ",head->data);
    head = head -> next;
  }
  printf("\n");
}

Data *insert_head(Data *head, int n) {
  head = (Data *)malloc (sizeof(Data));
  head -> next = NULL;
  int data;
  while(n --) {
    Data *p = (Data *)malloc(sizeof(Data));
    scanf("%d",&data);

    p -> data = data;
    p -> next = head -> next;
    head -> next = p;
  }
  return head;
}

Data *insert_tail(Data *head, int n) {
  head = (Data *)malloc(sizeof(Data));
  head -> next = NULL;
  Data *r = head;
  int data;
  while(n--) {
    Data *p = (Data *)malloc(sizeof(Data));
    scanf("%d", &data);

    p -> data = data;
    r -> next = p;
    r = p;
    p -> next = NULL;
  }
  return head;
}

Data *get_circle_list(Data *head) {
  Data *fast;
  Data *slow;
  fast  = head;
  slow = head;
  
  Data *meet = NULL;

  while (fast) {
    fast = fast -> next;
    slow = slow -> next;
    if (!fast) {
      return NULL;
    }

    fast = fast -> next;
    if(fast == slow) {
      meet = fast;
      break;
    }
  }
  
  if(meet == NULL) {
    return NULL;
  } else {
    while (!(head == meet)) {
      head = head -> next;
      meet = meet -> next;
    }
    return head;
  }
}

int main() {
  /*构造环形测试用例*/
  Data a1,a2,a3,a4,a5,a6,a7;
  a1.data = 1;
  a2.data = 2;
  a3.data = 3;
  a4.data = 4;
  a5.data = 5;
  a6.data = 6;
  a7.data = 7;

  a1.next = &a2;
  a2.next = &a3;
  a3.next = &a4;
  a4.next = &a5;
  a5.next = &a6;
  a6.next = &a7;
  /*构造环形,这里很明显环形的起点为5节点*/
  a7.next = &a5;

  printf("get circle node \n");
  Data *result = get_circle_list(&a1);
  printf("get circle node is %d\n",result -> data);
  return 0;
}

在图中找出一个环是比较基础的搜索算法。实现思路就是从每个未访问的节点运行 DFS深度优先遍历可用于检测图中的循环。具体程序可以参考:
https://blog.csdn.net/wat1r/article/details/119443596

用C语言实现的示例代码

#include <stdio.h>
#include <stdbool.h>

#define MAX_VERTEX_NUM 100
#define ERROR -1

// 无向图结构体
typedef struct {
    int vertex[MAX_VERTEX_NUM]; // 存放图的顶点
    int edge[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; // 存放图的边
    int vertexNum; // 顶点数量
    int edgeNum; // 边数量
} Graph;

// 初始化无向图
void initGraph(Graph *g, int vertex[], int edge[][MAX_VERTEX_NUM], int vertexNum, int edgeNum) {
    g->vertexNum = vertexNum;
    g->edgeNum = edgeNum;
    for (int i = 0; i < vertexNum; i++) {
        g->vertex[i] = vertex[i];
        for (int j = 0; j < vertexNum; j++) {
            g->edge[i][j] = edge[i][j];
        }
    }
}

// 输出无向图
void printGraph(Graph *g) {
    printf("顶点:");
    for (int i = 0; i < g->vertexNum; i++) {
        printf("%d ", g->vertex[i]);
    }
    printf("\n");
    printf("边:\n");
    for (int i = 0; i < g->vertexNum; i++) {
        for (int j = 0; j < g->vertexNum; j++) {
            printf("%d ", g->edge[i][j]);
        }
        printf("\n");
    }
}

// DFS遍历无向图,找出一个圈
bool dfs(Graph *g, int v, int visited[], int parent) {
    visited[v] = true;
    for (int i = 0; i < g->vertexNum; i++) {
        if (g->edge[v][i] == 1) {
            if (!visited[i]) {
                if (dfs(g, i, visited, v)) {
                    return true;
                }
            }
            else if (i != parent) {
                return true;
            }
        }
    }
    return false;
}

// 查找无向图中的一个圈
void findCycle(Graph *g) {
    int visited[MAX_VERTEX_NUM] = { false };
    int parent[MAX_VERTEX_NUM] = { -1 };
    bool hasCycle = false;
    for (int i = 0; i < g->vertexNum; i++) {
        if (!visited[i]) {
            hasCycle = dfs(g, i, visited, -1);
            if (hasCycle) {
                break;
            }
        }
    }
    if (hasCycle) {
        printf("无向图中存在一个圈。\n");
    }
    else {
        printf("无向图中不存在圈。\n");
    }
}

int main() {
    int vertex[] = { 1, 2, 3, 4, 5 };
    int edge[][MAX_VERTEX_NUM] = {
        { 0, 1, 0, 0, 1 },
        { 1, 0, 1, 0, 0 },
        { 0, 1, 0, 1, 0 },
        { 0, 0, 1, 0, 1 },
        { 1, 0, 0, 1, 0 }
    };
    int vertexNum = sizeof(vertex) / sizeof(int);
    int edgeNum = vertexNum * (vertexNum - 1) / 2 - 1; // 计算边数量
    Graph g;
    initGraph(&g, vertex, edge, vertexNum, edgeNum);
    printGraph(&g);
    findCycle(&g);
    return 0;
}