图类
Author:Joanh_Lan
Personal Blog Links:Joanh_LanのCSDN博客
备注:
个人复习版本
不保证完全正确,理性参考(不背锅i哦)
(:(:(:
欢迎阅读!!!
如果需要电子版请私信我,这个专栏不收取任何费用。
邻接矩阵
#define MaxVertexNum 100 //顶点数目的最大值
typedef char VertexType; //顶点对应的数据类型
typedef int EdgeType; //边所对应的数据类型
typedef struct {VertexType vex[MaxVertexNum]; //顶点表 EdgeType edge[MaxVertexNum][MaxVertexNum]; //邻接矩阵int vexnum, arcnum; //图的当前顶点数&边数
} MGraph;
邻接表
#define MaxVertexNum 100 //图中顶点数目的最大值
typedef struct ArcNode //边表结点
{int adjvex; //该弧所指向的顶点位置struct ArcNode *nextarc; //指向下一条弧的指针
} ArcNode;
typedef struct VNode //顶点表结点
{int data; //顶点信息ArcNode *firstarc; //指向第一条依附顶点的弧指针
} VNode, AdjList[MaxVertexNum];
typedef struct
{AdjList vertices; //邻接表int vexnum, arcnum; //图的顶点数 & 弧边数
} ALGraph; //ALGraph是以邻接表存图的图类型
十字链表
邻接多重表
邻接多重表是无向图的一种链式存储结构。在邻接表中,容易求得顶点和边的各种信息,但在邻接表中求两个顶点之间是否存在边而对边执行删除等操作时,需要分别在两个顶点的边表中遍历,效率较低。与十字链表类似,在邻接多重表中,每条边用一个结点表示,其结构如下所示。
-参考:2025王道数据结构-
图的遍历(搜索)
BFS
bool visited[MAX_VERTEX_NUM];
void BFSTraverse(Graph G) //对图G进行广度优先遍历for(i=0;i<G.vexnum;++i)visited[i]=FALSE;InitQueue(Q);
{//访问标记数组初始化//初始化辅助队列Q//从0号顶点开始遍历for(i = 0; i < G.vexnum; ++i)if(!visited[i])BFS(G, i);//对每个连通分量调用一次BFS//vi未访问过,从vi开始BFS
}
//广度优先遍历
void BFS(Graph G, int v)
{//从顶点v出发,广度优先遍历图Gvisit(v);//访问初始顶点vvisited[v] = TRUE;//对v做已访问标记Enqueue(Q, v);//顶点v入队列Qwhile(!isEmpty(Q)){DeQueue(Q, v);//顶点v出队列for(w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)) //检测v所有邻接点if(!visited[w]) //w为v的尚未访问的邻接顶点visit(w);//访问顶点w{visited[w] = TRUE; //对w做已访问标记EnQueue(Q,w); //顶点w入队列}//if}//while
}
DFS
树
//树的先根遍历
void PreOrder(TreeNode *R)
{if(R != NULL){visit(R); //访问根节点while(R还有下一个子树T)PreOrder(T);//先根遍历下一棵子树}
}
图
如果是连通图:
bool visited [MAX_VERTEX_NUM]; //访问标记数组
void DFS(Graph G, int v) //从顶点v出发,深度优先遍历图
{visit(v);//访问顶点visited[v] = TRUE; //设已访问标记{for(w = FirstNeighbor(G, v); w >= 0; w = NextNeighor(G, v, w))if(!visited[w]) //w为u的尚未访问的邻接顶点DFS(G, w);}
}
如果是非连通图(注意:这里可能出坑)
bool visited[MAX_VERTEX_NUM]; //访问标记数组void DFSTraverse(Graph G)//对图G进行深度优先遍历
{for(v = 0; v < G.vexnum; ++v)visited[v] = FALSE;//初始化已访问标记数据for(v = 0; v < G.vexnum; ++v)if(!visited[v])DFS(G, v);//本代码中是从v=0开始遍历
}void DFS(Graph G, int v) //从顶点v出发,深度优先遍历图G
{visit(v);//访问顶点vvisited[v] = TRUE; //设已访问标记for(w = FirstNeighbor(G, v); w >= 0; w = NextNeighor(G, v, w))if(!visited[w]) //w为u的尚未访问的邻接顶点DFS(G,w);
}
时间复杂度=访问各结点所需时间+探索各条边所需时间
邻接矩阵 \color{red}邻接矩阵 邻接矩阵存储的图:
访问 |V| 个顶点需要O(|V|)的时间
查找每个顶点的邻接点都需要O(|V|)的时间,⽽总共有|V|个顶点
时间复杂度= O ( ∣ V ∣ 2 ) \color{red}O(|V|^2) O(∣V∣2)
邻接表 \color{red}邻接表 邻接表存储的图:
访问 |V| 个顶点需要O(|V|)的时间
查找各个顶点的邻接点共需要O(|E|)的时间,
时间复杂度= O ( ∣ V ∣ + ∣ E ∣ ) \color{red}O(|V|+|E|) O(∣V∣+∣E∣)
注:
同⼀个图的 邻接矩阵 \color{red}邻接矩阵 邻接矩阵表示⽅式 唯⼀ \color{red}唯⼀ 唯⼀,因此 深度优先遍历序列唯⼀ \color{red}深度优先遍历序列唯⼀ 深度优先遍历序列唯⼀
同⼀个图 邻接表 \color{red}邻接表 邻接表表示⽅式 不唯⼀ \color{red}不唯⼀ 不唯⼀,因此 深度优先遍历序列不唯⼀ \color{red}深度优先遍历序列不唯⼀ 深度优先遍历序列不唯⼀
最小生成树
prim
#define MaxVertexNum 100 //顶点数目的最大值
typedef char VertexType; //顶点对应的数据类型
typedef int EdgeType; //边所对应的数据类型
typedef struct {VertexType vex[MaxVertexNum]; //顶点表 EdgeType edge[MaxVertexNum][MaxVertexNum]; //邻接矩阵int vexnum, arcnum; //图的当前顶点数&边数
} MGraph;int dist[MaxVertexNum]; // 存储其他点到当前最小生成树的距离
bool st[MaxVertexNum]; //存储每个点是否已经在生成树中
int prim(MGraph G) //返回最小生成树的权值
{for (int i = 0; i < MaxVertexNum; i++) dist[i] = 0x3f3f3f3f;int ans = 0;for (int i = 0; i < MaxVertexNum; i++){int t = -1;for (int j = 0; j < MaxVertexNum; j++)if (!st[j] && (t == -1 || dist[t] > dist[j])) t = j;if (i && dist[t] == 0x3f3f3f3f) return 0x3f3f3f3f; //不连通if (i) ans += dist[t];st[t] = true;for (int j = 0; j < MaxVertexNum; j++)dist[j] = min(dist[j], G.edge[t][j]);}return ans;
}
Kruskal
如果代码题真考到
按照题目给的图的定义,写个合适的sort替换下面的即可
这里只提供框架
int n, m; // n是点数,m是边数
int p[N]; // 并查集的父节点数组struct Edge // 存储边
{int a, b, w;bool operator< (const Edge &W)const{return w < W.w;}
}edges[M];int find(int x) // 并查集核心操作
{if (p[x] != x) p[x] = find(p[x]);return p[x];
}int kruskal()
{sort(edges, edges + m);for (int i = 1; i <= n; i ++ ) p[i] = i; // 初始化并查集int res = 0, cnt = 0;for (int i = 0; i < m; i ++ ){int a = edges[i].a, b = edges[i].b, w = edges[i].w;a = find(a), b = find(b);if (a != b) // 如果两个连通块不连通,则将这两个连通块合并{p[a] = b;res += w;cnt ++ ;}}if (cnt < n - 1) return INF; //不连通return res;
}
dijkstra
时间复杂是 O( n 2 + m n^2+m n2+m), n 表示点数,m 表示边数
#define MaxVertexNum 100 //顶点数目的最大值
typedef char VertexType; //顶点对应的数据类型
typedef int EdgeType; //边所对应的数据类型
typedef struct {VertexType vex[MaxVertexNum]; //顶点表 EdgeType edge[MaxVertexNum][MaxVertexNum]; //邻接矩阵int vexnum, arcnum; //图的当前顶点数&边数
} MGraph;int dist[MaxVertexNum]; // 存储1号点到每个点的最短距离
bool st[MaxVertexNum]; // 存储每个点的最短路是否已经确定int dijkstra(MGraph G, int p, int k) // p号点到k号点的最短路径,如果不存在返回-1
{for (int i = 0; i < MaxVertexNum; i++) dist[i] = 0x3f3f3f3f3;dist[p] = 0;for (int i = 0; i < MaxVertexNum; i++){int t = -1; //在还未确定最短路的点中,寻找距离最小的点for (int j = 0; j < MaxVertexNum; j++)if (!st[j] && (t == -1 || dist[t] > dist[j])) t = j;//用t更新其他点的距离for (int j = 0; j < MaxVertexNum; j++)dist[j] = min(dist[j], dist[t] + G.edge[t][j]);st[t] = true;}if (dist[k] == 0x3f3f3f3f) return -1;return dist[k];
}
floyd
时间复杂度:O( n 3 n^3 n3)
void floyd()
{for(int i = 1; i <= n; i++)for(int j = 1; j <= n; j++){dist[i][j] = map[i][j],//path[i][j] = 0; }for(int k = 1; k <= n; k++)for(int i = 1; i <= n; i++)for(int j = 1; j <= n; j++)if(dist[i][k] + dist[k][j] < dist[i][j]){dist[i][j] = dist[i][k] + dist[k][j];//path[i][j] = k; // path记录路径中的最大点}}
拓扑排序
请参考我之前的文章(点击即可转跳)