当前位置: 首页 > news >正文

C语言需要掌握的基础知识点之图

C语言需要掌握的基础知识点之图

图是一种非常重要的非线性数据结构,由顶点的集合和顶点之间边的集合组成。以下是C语言中图的详细介绍和实现。

图的基本概念

图的定义
顶点(Vertex):图的基本单元
边(Edge):顶点之间的连接
有向图:边有方向
无向图:边没有方向
权重图:边带有权值

图的表示方法

邻接矩阵

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>#define MAX_VERTICES 100
#define INF INT_MAX  // 表示无穷大typedef struct Graph {int numVertices;int adjacencyMatrix[MAX_VERTICES][MAX_VERTICES];
} Graph;// 初始化图
Graph* createGraph(int vertices) {Graph* graph = (Graph*)malloc(sizeof(Graph));graph->numVertices = vertices;// 初始化邻接矩阵for(int i = 0; i < vertices; i++) {for(int j = 0; j < vertices; j++) {if(i == j)graph->adjacencyMatrix[i][j] = 0;  // 对角线为0elsegraph->adjacencyMatrix[i][j] = INF; // 初始为无穷大}}return graph;
}// 添加边(无向图)
void addEdgeUndirected(Graph* graph, int src, int dest, int weight) {graph->adjacencyMatrix[src][dest] = weight;graph->adjacencyMatrix[dest][src] = weight;
}// 添加边(有向图)
void addEdgeDirected(Graph* graph, int src, int dest, int weight) {graph->adjacencyMatrix[src][dest] = weight;
}// 打印邻接矩阵
void printGraph(Graph* graph) {printf("邻接矩阵:\n");for(int i = 0; i < graph->numVertices; i++) {for(int j = 0; j < graph->numVertices; j++) {if(graph->adjacencyMatrix[i][j] == INF)printf("INF ");elseprintf("%3d ", graph->adjacencyMatrix[i][j]);}printf("\n");}
}

邻接表

// 邻接表节点
typedef struct AdjListNode {int dest;int weight;struct AdjListNode* next;
} AdjListNode;// 邻接表
typedef struct AdjList {AdjListNode* head;
} AdjList;// 图结构(邻接表)
typedef struct GraphList {int numVertices;AdjList* array;
} GraphList;// 创建邻接表节点
AdjListNode* createAdjListNode(int dest, int weight) {AdjListNode* newNode = (AdjListNode*)malloc(sizeof(AdjListNode));newNode->dest = dest;newNode->weight = weight;newNode->next = NULL;return newNode;
}// 创建图(邻接表)
GraphList* createGraphList(int vertices) {GraphList* graph = (GraphList*)malloc(sizeof(GraphList));graph->numVertices = vertices;graph->array = (AdjList*)malloc(vertices * sizeof(AdjList));for(int i = 0; i < vertices; i++) {graph->array[i].head = NULL;}return graph;
}// 添加边(无向图-邻接表)
void addEdgeListUndirected(GraphList* graph, int src, int dest, int weight) {// 添加从src到dest的边AdjListNode* newNode = createAdjListNode(dest, weight);newNode->next = graph->array[src].head;graph->array[src].head = newNode;// 添加从dest到src的边newNode = createAdjListNode(src, weight);newNode->next = graph->array[dest].head;graph->array[dest].head = newNode;
}// 添加边(有向图-邻接表)
void addEdgeListDirected(GraphList* graph, int src, int dest, int weight) {AdjListNode* newNode = createAdjListNode(dest, weight);newNode->next = graph->array[src].head;graph->array[src].head = newNode;
}// 打印邻接表
void printGraphList(GraphList* graph) {printf("邻接表:\n");for(int i = 0; i < graph->numVertices; i++) {AdjListNode* temp = graph->array[i].head;printf("顶点 %d: ", i);while(temp) {printf("-> %d(w:%d) ", temp->dest, temp->weight);temp = temp->next;}printf("\n");}
}

图的遍历算法

深度优先搜索(DFS)

// DFS递归实现(邻接矩阵)
void DFS_Matrix(Graph* graph, int vertex, int visited[]) {visited[vertex] = 1;printf("%d ", vertex);for(int i = 0; i < graph->numVertices; i++) {if(graph->adjacencyMatrix[vertex][i] != INF && !visited[i]) {DFS_Matrix(graph, i, visited);}}
}void DFSTraversal(Graph* graph, int startVertex) {int visited[MAX_VERTICES] = {0};printf("DFS遍历: ");DFS_Matrix(graph, startVertex, visited);printf("\n");
}

广度优先搜索(BFS)

// 队列实现
typedef struct Queue {int items[MAX_VERTICES];int front;int rear;
} Queue;Queue* createQueue() {Queue* q = (Queue*)malloc(sizeof(Queue));q->front = -1;q->rear = -1;return q;
}int isEmpty(Queue* q) {return q->rear == -1;
}void enqueue(Queue* q, int value) {if(q->rear == MAX_VERTICES - 1)printf("队列已满\n");else {if(q->front == -1)q->front = 0;q->rear++;q->items[q->rear] = value;}
}int dequeue(Queue* q) {int item;if(isEmpty(q)) {printf("队列为空\n");item = -1;} else {item = q->items[q->front];q->front++;if(q->front > q->rear) {q->front = q->rear = -1;}}return item;
}// BFS遍历(邻接矩阵)
void BFS_Matrix(Graph* graph, int startVertex) {int visited[MAX_VERTICES] = {0};Queue* q = createQueue();visited[startVertex] = 1;enqueue(q, startVertex);printf("BFS遍历: ");while(!isEmpty(q)) {int currentVertex = dequeue(q);printf("%d ", currentVertex);for(int i = 0; i < graph->numVertices; i++) {if(graph->adjacencyMatrix[currentVertex][i] != INF && !visited[i]) {visited[i] = 1;enqueue(q, i);}}}printf("\n");
}

图的最小生成树算法

Prim算法

// Prim算法求最小生成树
void primMST(Graph* graph) {int parent[MAX_VERTICES];    // 存储MSTint key[MAX_VERTICES];       // 权值数组int mstSet[MAX_VERTICES];    // 标记顶点是否在MST中// 初始化for(int i = 0; i < graph->numVertices; i++) {key[i] = INF;mstSet[i] = 0;}key[0] = 0;        // 从第一个顶点开始parent[0] = -1;    // 第一个顶点是根节点for(int count = 0; count < graph->numVertices - 1; count++) {// 选择最小权值的顶点int min = INF, minIndex;for(int v = 0; v < graph->numVertices; v++) {if(!mstSet[v] && key[v] < min) {min = key[v];minIndex = v;}}int u = minIndex;mstSet[u] = 1;// 更新相邻顶点的权值for(int v = 0; v < graph->numVertices; v++) {if(graph->adjacencyMatrix[u][v] != INF && !mstSet[v] && graph->adjacencyMatrix[u][v] < key[v]) {parent[v] = u;key[v] = graph->adjacencyMatrix[u][v];}}}// 打印MSTprintf("Prim算法 - 最小生成树:\n");for(int i = 1; i < graph->numVertices; i++) {printf("%d - %d : %d\n", parent[i], i, graph->adjacencyMatrix[i][parent[i]]);}
}

Kruskal算法

// 边的结构体
typedef struct Edge {int src, dest, weight;
} Edge;// 并查集结构
typedef struct Subset {int parent;int rank;
} Subset;// 查找根节点
int find(Subset subsets[], int i) {if(subsets[i].parent != i)subsets[i].parent = find(subsets, subsets[i].parent);return subsets[i].parent;
}// 合并两个集合
void unionSets(Subset subsets[], int x, int y) {int rootX = find(subsets, x);int rootY = find(subsets, y);if(subsets[rootX].rank < subsets[rootY].rank)subsets[rootX].parent = rootY;else if(subsets[rootX].rank > subsets[rootY].rank)subsets[rootY].parent = rootX;else {subsets[rootY].parent = rootX;subsets[rootX].rank++;}
}// 比较函数(用于排序)
int compareEdges(const void* a, const void* b) {Edge* edge1 = (Edge*)a;Edge* edge2 = (Edge*)b;return edge1->weight - edge2->weight;
}// Kruskal算法
void kruskalMST(Graph* graph) {int V = graph->numVertices;Edge result[V];  // 存储MST结果int e = 0;       // 结果数组的索引int i = 0;       // 排序后边的索引// 获取所有边Edge* edges = (Edge*)malloc(V * V * sizeof(Edge));int edgeCount = 0;for(int u = 0; u < V; u++) {for(int v = u + 1; v < V; v++) {if(graph->adjacencyMatrix[u][v] != INF) {edges[edgeCount].src = u;edges[edgeCount].dest = v;edges[edgeCount].weight = graph->adjacencyMatrix[u][v];edgeCount++;}}}// 按权值排序qsort(edges, edgeCount, sizeof(Edge), compareEdges);// 分配内存给并查集Subset* subsets = (Subset*)malloc(V * sizeof(Subset));// 初始化并查集for(int v = 0; v < V; v++) {subsets[v].parent = v;subsets[v].rank = 0;}// 处理每条边while(e < V - 1 && i < edgeCount) {Edge nextEdge = edges[i++];int x = find(subsets, nextEdge.src);int y = find(subsets, nextEdge.dest);// 如果不形成环,加入MSTif(x != y) {result[e++] = nextEdge;unionSets(subsets, x, y);}}// 打印MSTprintf("Kruskal算法 - 最小生成树:\n");int minimumCost = 0;for(i = 0; i < e; i++) {printf("%d - %d : %d\n", result[i].src, result[i].dest, result[i].weight);minimumCost += result[i].weight;}printf("最小生成树总权值: %d\n", minimumCost);free(edges);free(subsets);
}

最短路径算法

Dijkstra算法

// Dijkstra算法求单源最短路径
void dijkstra(Graph* graph, int src) {int dist[MAX_VERTICES];    // 最短距离数组int visited[MAX_VERTICES]; // 已访问标记// 初始化for(int i = 0; i < graph->numVertices; i++) {dist[i] = INF;visited[i] = 0;}dist[src] = 0;for(int count = 0; count < graph->numVertices - 1; count++) {// 选择最小距离的顶点int min = INF, minIndex;for(int v = 0; v < graph->numVertices; v++) {if(!visited[v] && dist[v] <= min) {min = dist[v];minIndex = v;}}int u = minIndex;visited[u] = 1;// 更新相邻顶点的距离for(int v = 0; v < graph->numVertices; v++) {if(!visited[v] && graph->adjacencyMatrix[u][v] != INF && dist[u] != INF && dist[u] + graph->adjacencyMatrix[u][v] < dist[v]) {dist[v] = dist[u] + graph->adjacencyMatrix[u][v];}}}// 打印最短路径printf("Dijkstra算法 - 从顶点%d到各顶点的最短距离:\n", src);for(int i = 0; i < graph->numVertices; i++) {if(dist[i] == INF)printf("到顶点%d: 不可达\n", i);elseprintf("到顶点%d: %d\n", i, dist[i]);}
}

Floyd-Warshall算法

// Floyd-Warshall算法求所有顶点对最短路径
void floydWarshall(Graph* graph) {int dist[MAX_VERTICES][MAX_VERTICES];int V = graph->numVertices;// 初始化距离矩阵for(int i = 0; i < V; i++) {for(int j = 0; j < V; j++) {dist[i][j] = graph->adjacencyMatrix[i][j];}}// Floyd-Warshall算法核心for(int k = 0; k < V; k++) {for(int i = 0; i < V; i++) {for(int j = 0; j < V; j++) {if(dist[i][k] != INF && dist[k][j] != INF && dist[i][k] + dist[k][j] < dist[i][j]) {dist[i][j] = dist[i][k] + dist[k][j];}}}}// 打印结果printf("Floyd-Warshall算法 - 所有顶点对最短距离:\n");for(int i = 0; i < V; i++) {for(int j = 0; j < V; j++) {if(dist[i][j] == INF)printf("INF ");elseprintf("%3d ", dist[i][j]);}printf("\n");}
}

拓扑排序

// 拓扑排序(邻接表)
void topologicalSortUtil(GraphList* graph, int v, int visited[], int stack[], int* top) {visited[v] = 1;AdjListNode* temp = graph->array[v].head;while(temp != NULL) {int adjVertex = temp->dest;if(!visited[adjVertex]) {topologicalSortUtil(graph, adjVertex, visited, stack, top);}temp = temp->next;}stack[++(*top)] = v;
}void topologicalSort(GraphList* graph) {int stack[MAX_VERTICES];int top = -1;int visited[MAX_VERTICES] = {0};for(int i = 0; i < graph->numVertices; i++) {if(!visited[i]) {topologicalSortUtil(graph, i, visited, stack, &top);}}printf("拓扑排序: ");while(top >= 0) {printf("%d ", stack[top--]);}printf("\n");
}

完整示例程序

int main() {int V = 5;  // 顶点数// 创建图(邻接矩阵)Graph* graph = createGraph(V);// 添加边(无向图)addEdgeUndirected(graph, 0, 1, 2);addEdgeUndirected(graph, 0, 3, 6);addEdgeUndirected(graph, 1, 2, 3);addEdgeUndirected(graph, 1, 3, 8);addEdgeUndirected(graph, 1, 4, 5);addEdgeUndirected(graph, 2, 4, 7);addEdgeUndirected(graph, 3, 4, 9);// 打印图printGraph(graph);// 图遍历DFSTraversal(graph, 0);BFS_Matrix(graph, 0);// 最小生成树primMST(graph);kruskalMST(graph);// 最短路径dijkstra(graph, 0);floydWarshall(graph);// 创建有向图进行拓扑排序GraphList* graphList = createGraphList(6);addEdgeListDirected(graphList, 5, 2, 1);addEdgeListDirected(graphList, 5, 0, 1);addEdgeListDirected(graphList, 4, 0, 1);addEdgeListDirected(graphList, 4, 1, 1);addEdgeListDirected(graphList, 2, 3, 1);addEdgeListDirected(graphList, 3, 1, 1);printGraphList(graphList);topologicalSort(graphList);// 释放内存free(graph);return 0;
}

图的应用场景

在这里插入图片描述

http://www.dtcms.com/a/524292.html

相关文章:

  • 做一个类似京东的网站海外注册公司
  • python舆情分析可视化系统 情感分析 微博 爬虫 scrapy爬虫技术 朴素贝叶斯分类算法大数据 计算机✅
  • 压缩与缓存调优实战指南:从0到1根治性能瓶颈(六)
  • 做百度手机网站优化点asp网站制作教程
  • element+vue3 table上下左右键切换input和select
  • 元萝卜 1.0.27| 免Root,XP模块框架,支持应用多开分身,一键微信平板模式
  • 长春企业网站seo珠海企业官网设计制作
  • MySQL 函数详细说明
  • 《Memcached 连接:深入理解与优化实践》
  • C++ EigenSolver无优化模式下报错分析
  • 数据结构——折半插入排序
  • io_uring 快吗? Postgres 17 与 18 的基准测试
  • 国产数据库替代MongoDB:政务电子证照新选择
  • 甘孜建设网站集团响应式网站建设
  • 枸杞网站建设方案2024年即将上市的手机
  • Git 版本回退 reset --mixed 命令
  • 博途DWORD中包含word ,字节,位的关系
  • Java Character 类详解
  • 【数据结构】队列“0”基础知识讲解 + 实战演练
  • 【生活】秋冬季节,鼻子很干结痂,扣掉鼻孔干痂流血,鼻塞等护理方法
  • 网站关键词公司百度关键词查询
  • 大模型通识
  • 346. 执行操作后元素的最高频率 I
  • 一些常用的linux操作指令
  • jeecg表单设计器js增强实现效果案例;点按钮出弹框,iframe嵌套,数据传输等
  • Spring IOC源码篇八 核心方法prepareBeanFactory
  • S10--循环队列
  • 基于月尺度水分平衡模型的葡萄园规划与行间管理决策
  • 网站的前期推广网页设计与制作源代码
  • PY32F040单片机介绍(3)