图的存储与遍历
图的存储#
邻接矩阵#
图是一种多对多的数据结构,对于一个有n个顶点的有向图采用n阶方阵来表示。M[i][j]
为真则存在边m->n,否则不存在边;或者,用M[i][j]
存储边的权值。
无向图的一条边可以当作一对有向边,或者采用三角矩阵存储无向图。
十字链表#
图由顶点的集合和每个顶点的一组边来表示,可以使用数组存储所有顶点。可以用链表存储一个顶点的出边,顶点作为链表的头结点。同理,具有相同终点的一组边也可以组成一个链表,终点可以作为链表头结点。
这样,每个边节点都属于两个链表(同起点和同终点),可以形象的表示成一个十字状结构。
边定义:
typedef struct Edge {
int headvex; //起点索引
int tailvex; //终点索引
struct Edge *outlink; //出边链表的next指针
struct Edge *inlink; //入边链表的next指针
int val; //权值
} Edge;
顶点定义:
typedef struct {
int val;
Edge *firstin; //入边链表头节点
Edge *firstout; //出边链表头节点
} Vertex;
定义建立链表的函数
void getOList(Vertex *vertexs, int m) {
int i, j, k;
Edge *edge;
for (i = 0; i < m; i++) {
vertexs[i].firstin = NULL;
vertexs[i].firstout = NULL;
}
while (scanf("%d %d", &i, &j) != EOF) {
//append
edge = (Edge *)malloc(sizeof(Edge));
edge->headvex = i;
edge->tailvex = j;
appendOutEdge(&vertexs[i], edge); //添加到出边链表中
appendInEdge (&vertexs[j], edge); //添加到入边链表中
}
}
工具函数:
void appendInEdge(Vertex *vertex, Edge *edge) {
Edge *ptr;
edge->inlink = NULL;
if(vertex->firstin) {
ptr = vertex->firstin;
while(ptr->inlink) {
ptr = ptr->inlink;
}
ptr->inlink = edge;
}
else {
vertex->firstin = edge;
}
}
void appendOutEdge(Vertex *vertex, Edge *edge) {
Edge *ptr;
edge->outlink = NULL;
if(vertex->firstout) {
ptr = vertex->firstout;
while(ptr->outlink) {
ptr = ptr->outlink;
}
ptr->outlink = edge;
}
else {
vertex->firstout = edge;
}
}
访问指定顶点:
int getEdge(Vertex *vertexs, int x, int y) {
Edge *ptr;
ptr = vertexs[x].firstout;
while (ptr) {
if (ptr->tailvex == y) {
return ptr->val;
}
}
return -1;
}
图的遍历#
图的遍历是指不重不漏的按照顶点之间的边访问所有顶点。图的的遍历与树的遍历类似,但是需要标记已访问过的顶点。
图的遍历只需要访问顶点和访问边的接口即可,与具体存储方式无关。为了效率起见这里还是提供了十字链表专用的遍历算法。
深度优先搜索#
int visited[M];
void DFS(int **matrix, int m) {
int i;
for (i = 0; i < M; i++) {
visited[i] = 0;
}
for (i = 0; i < m; i++) {
if (!visited[i]) {
doDFS(matrix,m,i);
}
}
}
void doDFS(int **matrix, int m, int v) {
int i;
visited[v] = 1;
printf("%d\n",v + 1);
for (i = 0; i < m; i++) {
if (matrix[v][i]) {
if (!visited[i]) {
doDFS(matrix, m, i);
}
}
}
}
十字链表:
int visited[M];
void DFS(Vertex *vertexs, int m) {
int i;
for (i = 0; i < M; i++) {
visited[i] = 0;
}
for (i = 0; i < m; i++) {
if (!visited[i]) {
doDFS(vertexs,m,i);
}
}
}
void doDFS(Vertex *vertexs, int m, int v) {
int j;
Edge *ptr = vertexs[v].firstout;
visited[v] = 1;
printf("%d\n",v + 1);
while (ptr) {
j = ptr->tailvex;
doDFS(vertexs, m, j);
ptr = ptr->outlink;
}
}
广度优先搜索#
void BFS(int **matrix, int m) {
int i, j;
int front = 0, back = 0,que[M * M] = {0};
for (i = 0; i < M; i++) {
visited[i] = 0;
}
for (i = 0; i < m; i++) {
if (!visited[i]) {
visited[i] = 1;
printf("%d\n", i + 1);
que[back++] = i;
while (front < back) {
front++;
for ( j = 0; j < m; j++) {
if (!matrix[i][j]) {
continue;
}
if (!visited[i]) {
visited[i] = 1;
printf("%d\n", i + 1);
que[back++] = i;
}
}
}
}
}
}
十字链表:
void BFS(Vertex *vertexs, int m) {
int i, j;
int front = 0, back = 0,que[M * M] = {0};
Edge *ptr;
for (i = 0; i < M; i++) {
visited[i] = 0;
}
for (i = 0; i < m; i++) {
if (!visited[i]) {
visited[i] = 1;
printf("%d\n", i);
que[back++] = i;
while (front < back) {
front++;
ptr = vertexs[i].firstout;
while (ptr) {
if (!visited[i]) {
visited[i] = 1;
printf("%d\n", i);
que[back++] = i;
}
ptr = ptr->outlink;
}
}
}
}
}
完整源代码#
邻接矩阵:
#include <stdio.h>
#define M 16
void getGraph(int **matrix, int *m) {
int i,j;
scanf("%d", m);
for (i = 0; i < *m; i++) {
for (j = 0; j < *m; j++) {
scanf("%d",&matrix[i][j]);
}
}
}
void putGraph(int **matrix, int m) {
int i, j;
for (i = 0; i < m; i++) {
for (j = 0; j < m; j++) {
printf("%d ", matrix[i][j]);
}
putchar('\n');
}
}
int visited[M];
void DFS(int **matrix, int m) {
int i;
for (i = 0; i < M; i++) {
visited[i] = 0;
}
for (i = 0; i < m; i++) {
if (!visited[i]) {
doDFS(matrix,m,i);
}
}
}
void doDFS(int **matrix, int m, int v) {
int i;
visited[v] = 1;
printf("%d\n",v + 1);
for (i = 0; i < m; i++) {
if (matrix[v][i]) {
if (!visited[i]) {
doDFS(matrix, m, i);
}
}
}
}
void BFS(int **matrix, int m) {
int i, j;
int front = 0, back = 0,que[M * M] = {0};
for (i = 0; i < M; i++) {
visited[i] = 0;
}
for (i = 0; i < m; i++) {
if (!visited[i]) {
visited[i] = 1;
printf("%d\n", i + 1);
que[back++] = i;
while (front < back) {
front++;
for ( j = 0; j < m; j++) {
if (!matrix[i][j]) {
continue;
}
if (!visited[i]) {
visited[i] = 1;
printf("%d\n", i + 1);
que[back++] = i;
}
}
}
}
}
}
int main() {
int m = 2, matrix[M][M] = {0};
getGraph(matrix, &m);
DFS(matrix, m);
BFS(matrix, m);
}
十字链表:
#include <stdio.h>
#include <stdlib.h>
#define M 16
typedef struct Edge {
int headvex;
int tailvex;
struct Edge *outlink;
struct Edge *inlink;
int val;
} Edge;
typedef struct {
int val;
Edge *firstin;
Edge *firstout;
} Vertex;
void appendInEdge(Vertex *vertex, Edge *edge) {
Edge *ptr;
edge->inlink = NULL;
if(vertex->firstin) {
ptr = vertex->firstin;
while(ptr->inlink) {
ptr = ptr->inlink;
}
ptr->inlink = edge;
}
else {
vertex->firstin = edge;
}
}
void appendOutEdge(Vertex *vertex, Edge *edge) {
Edge *ptr;
edge->outlink = NULL;
if(vertex->firstout) {
ptr = vertex->firstout;
while(ptr->outlink) {
ptr = ptr->outlink;
}
ptr->outlink = edge;
}
else {
vertex->firstout = edge;
}
}
void getOList(Vertex *vertexs, int m) {
int i, j, k;
Edge *edge;
for (i = 0; i < m; i++) {
vertexs[i].firstin = NULL;
vertexs[i].firstout = NULL;
}
while (scanf("%d %d", &i, &j) != EOF) {
//append
edge = (Edge *)malloc(sizeof(Edge));
edge->headvex = i;
edge->tailvex = j;
appendOutEdge(&vertexs[i], edge);
appendInEdge (&vertexs[j], edge);
}
}
int getEdge(Vertex *vertexs, int x, int y) {
Edge *ptr;
ptr = vertexs[x].firstout;
while (ptr) {
if (ptr->tailvex == y) {
return ptr->val;
}
}
return -1;
}
void putOList(Vertex *vertexs, int m) {
int i, j;
Edge *ptr;
//in
for (j = 0; j < m; j++) {
ptr = vertexs[j].firstin;
while (ptr) {
i = ptr->headvex;
printf("%d %d\n", i, j);
ptr = ptr->inlink;
}
}
printf("out:\n");
//out
for (i = 0; i < m; i++) {
ptr = vertexs[i].firstout;
while (ptr) {
j = ptr->tailvex;
printf("%d %d\n",i , j);
ptr = ptr->outlink;
}
}
printf("\n");
}
int visited[M];
void DFS(Vertex *vertexs, int m) {
int i;
for (i = 0; i < M; i++) {
visited[i] = 0;
}
for (i = 0; i < m; i++) {
if (!visited[i]) {
doDFS(vertexs,m,i);
}
}
}
void doDFS(Vertex *vertexs, int m, int v) {
int j;
Edge *ptr = vertexs[v].firstout;
visited[v] = 1;
printf("%d\n",v + 1);
while (ptr) {
j = ptr->tailvex;
doDFS(vertexs, m, j);
ptr = ptr->outlink;
}
}
void BFS(Vertex *vertexs, int m) {
int i, j;
int front = 0, back = 0,que[M * M] = {0};
Edge *ptr;
for (i = 0; i < M; i++) {
visited[i] = 0;
}
for (i = 0; i < m; i++) {
if (!visited[i]) {
visited[i] = 1;
printf("%d\n", i);
que[back++] = i;
while (front < back) {
front++;
ptr = vertexs[i].firstout;
while (ptr) {
if (!visited[i]) {
visited[i] = 1;
printf("%d\n", i);
que[back++] = i;
}
ptr = ptr->outlink;
}
}
}
}
}
int main() {
int i, j, m;
Vertex vertexs[M];
scanf("%d",&m);
getOList(vertexs, m);
putOList(vertexs, m);
BFS(vertexs,m);
return 0;
}
作者:finley
出处:https://www.cnblogs.com/Finley/p/5236371.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南