日期:2023.10.12
第四天
邻接矩阵:
/*
邻接矩阵实现法:
1.不要忘记可能在未被访问过的集合中,找不到最小距离的点,这时函数应该直接返回;
2. 时间复杂度为 O(V*(V+V)) = O(V*V)
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 1000; //最大顶点数
const int INF = 0x3f3f3f3f;
bool vis[N] = {0}; // 标记已访问过的点
int d[N]; //存储每个点到起点的距离
int G[N][N];
int n;
void Dijkstra(int s) { //传入起点编号
//初始时,把起点以外的所有点到起点距离都设置为无穷大
memset(d, 0x3f, sizeof(d));
d[s] = 0;
//默认G图中无边的话,边长是INF
for(int i = 0; i < n; i++) { //已访问过的点的集合到达n个点时,循环结束
//1.找到未访问过的顶点中,距离起点最小的值
int u = -1, MIN = INF; //u记录最小距离的顶点编号,MIN记录最小距离的值
//这个循环遍历所有点,找到最小距离的点
for(int j = 0; j < n; j++) {
if(vis[j] == 0 && d[j] < MIN) {
u = j;
MIN = d[j];
}
}
//注意可能u可能还是-1,表示找不到小于INF的d[u],说明剩下的顶点和起点S不连通
if(u == -1) return ;
vis[u] = 1;
//在未被访问过的点中,找与u相连的点 ,更新它到起点的距离;
for(int v = 0; v < n; v++) {
if(G[u][v] != INF && vis[v] == 0) {
d[v] = min(d[v], d[u] + G[u][v]);
}
}
}
}
int main(void) {
return 0;
}
邻接表:
/*
揣摩一下:
存储一条边时,就是两个顶点,一条边长;
邻接矩阵存储的话,顶点信息就是下表,然后元素的值是边长;
邻接表存储: Adj[u][i]的i 是没有用处的,只能选择存储信息在Adj[u][i]的值,
这个值就是顶点u相连的顶点编号,所以如何还需要存储边长,邻接表的元素就得是结构体;
当需要存储图的边长信息时,邻接表的元素需要是结构体
*/
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 100010;//最大顶点数
struct Node {
int v; //顶点编号
int dis; //边权
};
vector<Node> Adj[N];
bool vis[N] = {0};
int d[N];
int n;
void Dijkstra(int s) {
memset(d, 0x3f, sizeof(d));
d[s] = 0;
for(int i = 0; i < n; i++) {
int u = -1, MIN = INF;
for(int j = 0; j < n; j++) {
if(vis[j] == 0 && d[j] < MIN) {
u = j;
MIN = d[j];
}
}
if(u == -1) return ;
//更新和u相连的点的最短距离
for(int j = 0; j < Adj[u].size(); j++) {
int v = Adj[u][j].v;
if(vis[v] == 0) {
d[v] = min(d[v], d[u] + Adj[u][v].dis);
}
}
}
}
int main(void) {
return 0;
}
注意:
1.邻接表存储图时,如果需要存储边权,就得以结构体为链表元素;
2.邻接表的内层循环的第二个循环,执行n次,刚好遍历完所有的边,所以复杂度是O(E),所以总时间复杂度是O(N*N+E);
3.算法第一步是找到不在集合S内的,距离起点最近的点,这个点可能找不到,代表剩下的所有点与起点不连通,需要特判一下。