图(邻接表)-(DFS/BFS)-Dijkstra算法
基于一道简单实验,学习用邻接表结构储存图,并且包含DFS/BFS两种遍历方式,以及Dijkstra算法(朴素版)在本题的使用。

头文件(以及相关内容)
cpp
#include <cstdio>
#include <cstdlib>
#define MAX_VERTEX_NUM 20
#define INFINITY 0x3f3f3f3f
typedef char VertexType;
1.邻接表的构建
包含三个部分:
- 边节点
- 所指向边节点的索引(adjvex)
- 指向下一边节点的指针(nextarc)
- 顶点节点
- 储存该节点的信息(data)-----节点名称等
- 指向边节点的指针(firstarc)
- 组合成邻接表
- 顶点数组(vertices)
- 顶点数(vexnum)
- 边数(arcnum)
代码如下:
cpp
// 边节点结构
typedef struct ArcNode
{
// 该边指向的点节点的索引
int adjvex;
// 权值
int value;
// 指向下一个边节点的指针
struct ArcNode *nextarc;
} ArcNode;
// 顶点节点的结构
typedef struct VNode
{
// 顶点节点的数据(顶点节点的名称)
VertexType data;
// 指向的第一个边节点
ArcNode *firstarc;
} VNode, adjList[MAX_VERTEX_NUM];
// 邻接表表示的图的结构
typedef struct ALGraph
{
// 顶点数组
adjList vertices;
// 顶点数,边数
int vexnum, arcnum;
} ALGraph;
2.两种遍历
复用函数(vis --- 表示该顶点是否被访问;Visit函数 --- 访问该节点后的行为:打印节点信息)
cpp
int vis[MAX_VERTEX_NUM];
void Visit(const ALGraph &G,int v) {
printf("%c ",G.vertices[v].data);
}
DFS遍历
cpp
void DFS(const ALGraph &G,int v) {
vis[v]=1;
Visit(G,v);
ArcNode* p=G.vertices[v].firstarc;
while(p!=NULL) {
int w=p->adjvex;
if(!vis[w]) {
DFS(G,w);
}
p=p->nextarc;
}
}
void DFSTraverse(const ALGraph &G) {
int n=G.vexnum;
for(int i=0; i<n; i++) {
vis[i]=0;
}
for(int i=0; i<n; i++) {
if(!vis[i]) {
DFS(G,i);
}
}
}
BFS遍历
(懒的补充写队列中的入队、出队函数,也不用STL,采用双指针的移动来模拟入队、出队 )
注:front++相当于出队,rear++相当于入队
cpp
void BFS(const ALGraph &G,int v) {
int Queue[MAX_VERTEX_NUM];
int front=0,rear=0;
vis[v]=1;
Visit(G,v);
Queue[rear++]=v;
while(front<rear) {
int u=Queue[front];
front++;
ArcNode* p=G.vertices[u].firstarc;
while(p!=NULL) {
int w=p->adjvex;
if(!vis[w]) {
vis[w]=1;
Visit(G,w);
Queue[rear++]=w;
}
p=p->nextarc;
}
}
}
void BFSTraverse(const ALGraph &G) {
int n=G.vexnum;
for(int i=0; i<n; i++) {
vis[i]=0;
}
for(int i=0; i<n; i++) {
if(!vis[i]) {
BFS(G,i);
}
}
}
3.Dijkstra算法(朴素版)
主要核心:
- 初始化距离:设定源节点到自身的距离为 0,到其他所有节点的距离为 (INFINITY:0x3f3f3f3f)。
- 贪心选择:每次从未确定最短路径的节点中,选择当前距离源节点最近的节点 u,将其标记为 "已确定最短路径"。(dist[u])
- 松弛操作 :对节点 u 的所有邻接节点 v,尝试通过 u 更新 v 的最短距离。
松弛条件:若 dist[v] > dist[u] + w(u, v),则更新 dist[v] = dist[u] + w(u, v)。 - 重复步骤 2-3:直到所有节点都被标记为 "已确定最短路径"。
Dijkstra 算法贪心选择正确性证明:
- 前提
- 图中所有边权非负;
- S:已确定最短路径的节点集合;
- dist [u]:当前已知 s 到 u 的最短距离上界。
- 反证法证明
假设:选 u 时,存在更短的 s→u 路径 P,长度<dist [u]。拆分路径 P:s→...→x(x∈S,P 上最后一个在 S 中的节点)→y(y∉S,P 上第一个不在 S 中的节点)→...→u。
因 x∈S,其最短路径已确定(dist [x] = 真实最短距离);又边权非负,所以 s→y 的真实最短距离 ≤ s→x→y 的长度 ≤ 路径 P 的长度(y 到 u 的路径权值≥0,不会缩短)。
结合假设 "P 长度<dist [u]",可推出:s→y 的真实最短距离 < dist [u]。但 dist [y] 是 s→y 的距离上界(dist [y]≥真实最短距离),因此 dist [y] < dist [u]。
这与「u 是当前未确定节点中 dist 最小的节点」矛盾,故假设不成立。 - 结论
每次选的 u,其当前 dist [u] 就是 s 到 u 的最短路径,后续不会被更新。
(代码如下:)
cpp
//通过Dijkstra算法求最短路径
int Dijkstra(const ALGraph &G,int start) {
int n=G.vexnum;
int* dist=(int*)malloc(n*sizeof(int)); //dist[i]与起点的距离
int* visited=(int*)malloc(n*sizeof(int));//visited[i]==1时,最短路径确定
//初始化
for(int i=0; i<n; i++) {
dist[i]=INFINITY;
visited[i]=0;
}
dist[start]=0;
for(int i=0; i<n; i++) {
int u=-1;
int min_dist=INFINITY;
//(贪心选择)
//从未确定的顶点中,找距离起点最近的顶点,找到后该顶点距离起点的最短距离即可确定
for(int j=0; j<n; j++) {
if(!visited[j]&&dist[j]<min_dist) {
min_dist=dist[j];
u=j;
}
}
if(u==-1) break;
visited[u]=1;
if(u==n-1) break;
//松弛操作
ArcNode* p=G.vertices[u].firstarc;
while(p!=NULL) {
int v=p->adjvex;
int w=p->value;
if(!visited[v] && dist[u]!=INFINITY && dist[u]+w<dist[v]) {
dist[v]=dist[u]+w;
}
p=p->nextarc;
}
}
int result=dist[n-1];
free(dist);
free(visited);
return result;
}
4.综上所述(完整代码如下)
cpp
#include<cstdio>
#include<cstdlib>
#define MAX_VERTEX_NUM 20
#define INFINITY 0x3f3f3f3f
typedef char VertexType;
//边节点结构
typedef struct ArcNode {
//该边指向的点节点的索引
int adjvex;
//权值
int value;
//指向下一个边节点的指针
struct ArcNode* nextarc;
} ArcNode;
//顶点节点的结构
typedef struct VNode {
//顶点节点的数据(顶点节点的名称)
VertexType data;
//指向的第一个边节点
ArcNode* firstarc;
} VNode,adjList[MAX_VERTEX_NUM];
//邻接表表示的图的结构
typedef struct ALGraph {
//顶点数组
adjList vertices;
//顶点数,边数
int vexnum,arcnum;
} ALGraph;
//返回节点在数组中的索引
int LocateVex(const ALGraph &G,VertexType V) {
for(int i=0; i<G.vexnum; i++) {
if(G.vertices[i].data==V)
return i;
}
return -1;
}
//图的创建
int CreateDG(ALGraph &G) {
//输入顶点数和边数
printf("请输入顶点数与边数:\n");
scanf("%d %d",&G.vexnum,&G.arcnum);
getchar();
//输入顶点信息(顶点的名称等)
printf("请输入%d个顶点的信息:\n",G.vexnum);
for(int i=0; i<G.vexnum; i++) {
scanf("%c",&G.vertices[i].data);
getchar();
//初始化
G.vertices[i].firstarc=NULL;
}
//输入边的信息
VertexType V1,V2;
int v;
ArcNode* p;
printf("请输入%d条边的信息:\n",G.arcnum);
for(int k=0; k<G.arcnum; k++) {
scanf("%c %c %d",&V1,&V2,&v);
getchar();
int i=LocateVex(G,V1);
int j=LocateVex(G,V2);
if(i==-1||j==-1)
return 0;
p=(ArcNode*)malloc(sizeof(ArcNode));
p->adjvex=j;
p->value=v;
//头插法
p->nextarc=G.vertices[i].firstarc;
G.vertices[i].firstarc=p;
}
return 1;
}
//遍历
int vis[MAX_VERTEX_NUM];
void Visit(const ALGraph &G,int v) {
printf("%c ",G.vertices[v].data);
}
//DFS
void DFS(const ALGraph &G,int v) {
vis[v]=1;
Visit(G,v);
ArcNode* p=G.vertices[v].firstarc;
while(p!=NULL) {
int w=p->adjvex;
if(!vis[w]) {
DFS(G,w);
}
p=p->nextarc;
}
}
void DFSTraverse(const ALGraph &G) {
int n=G.vexnum;
for(int i=0; i<n; i++) {
vis[i]=0;
}
for(int i=0; i<n; i++) {
if(!vis[i]) {
DFS(G,i);
}
}
}
//BFS
void BFS(const ALGraph &G,int v) {
int Queue[MAX_VERTEX_NUM];
int front=0,rear=0;
vis[v]=1;
Visit(G,v);
Queue[rear++]=v;
while(front<rear) {
int u=Queue[front];
front++;
ArcNode* p=G.vertices[u].firstarc;
while(p!=NULL) {
int w=p->adjvex;
if(!vis[w]) {
vis[w]=1;
Visit(G,w);
Queue[rear++]=w;
}
p=p->nextarc;
}
}
}
void BFSTraverse(const ALGraph &G) {
int n=G.vexnum;
for(int i=0; i<n; i++) {
vis[i]=0;
}
for(int i=0; i<n; i++) {
if(!vis[i]) {
BFS(G,i);
}
}
}
//通过Dijkstra算法求最短路径
int Dijkstra(const ALGraph &G,int start) {
int n=G.vexnum;
int* dist=(int*)malloc(n*sizeof(int)); //dist[i]与起点的距离
int* visited=(int*)malloc(n*sizeof(int));//visited[i]==1时,最短路径确定
//初始化
for(int i=0; i<n; i++) {
dist[i]=INFINITY;
visited[i]=0;
}
dist[start]=0;
for(int i=0; i<n; i++) {
int u=-1;
int min_dist=INFINITY;
//(贪心选择)
//从未确定的顶点中,找距离起点最近的顶点,找到后该顶点距离起点的最短距离即可确定
for(int j=0; j<n; j++) {
if(!visited[j]&&dist[j]<min_dist) {
min_dist=dist[j];
u=j;
}
}
if(u==-1) break;
visited[u]=1;
if(u==n-1) break;
//松弛操作
ArcNode* p=G.vertices[u].firstarc;
while(p!=NULL) {
int v=p->adjvex;
int w=p->value;
if(!visited[v] && dist[u]!=INFINITY && dist[u]+w<dist[v]) {
dist[v]=dist[u]+w;
}
p=p->nextarc;
}
}
int result=dist[n-1];
free(dist);
free(visited);
return result;
}
//主程序
int main() {
ALGraph G;
if(CreateDG(G)) {
printf("成功\n");
}
else printf("失败\n");
//DFS遍历
printf("DFS遍历结果:");
DFSTraverse(G);
printf("\n");
//BFS遍历
printf("BFS遍历结果:");
BFSTraverse(G);
printf("\n");
int min=Dijkstra(G,0);
printf("%d",min);
return 0;
}
5.补充(用DFS/BFS解决该题)
DFS
cpp
#include<cstdio>
#include<cstdlib>
#define MAX_VERTEX_NUM 20
#define INFINITY 0x3f3f3f3f
typedef char VertexType;
//边节点
typedef struct ArcNode{
int adjvex;
int value;
struct ArcNode* nextarc;
}ArcNode;
//顶点节点
typedef struct VNode{
VertexType data;
ArcNode* firstarc;
}VNode,adjList[MAX_VERTEX_NUM];
//构建邻接表
typedef struct ALgraph{
adjList vertices;
int vexnum,arcnum;
}ALgraph;
//返回节点的索引
int LocateVex(const ALgraph &G,VertexType e){
for(int i=0;i<G.vexnum;i++){
if(G.vertices[i].data==e){
return i;
}
}
return -1;
}
//创建图
int CreateDG(ALgraph &G){
printf("请输入顶点数和边数:\n");
scanf("%d %d",&G.vexnum,&G.arcnum);
getchar();
printf("请输入顶点的信息:\n");
for(int i=0;i<G.vexnum;i++){
scanf("%c",&G.vertices[i].data);
getchar();
G.vertices[i].firstarc=NULL;
}
printf("请输入边的关系:\n");
ArcNode* p;
VertexType V1,V2;
int v;
for(int k=0;k<G.arcnum;k++){
scanf("%c %c %d",&V1,&V2,&v);
getchar();
int i=LocateVex(G,V1);
int j=LocateVex(G,V2);
if(i==-1||j==-1){
return 0;
}
p=(ArcNode*)malloc(sizeof(ArcNode));
p->adjvex=j;
p->value=v;
p->nextarc=G.vertices[i].firstarc;
G.vertices[i].firstarc=p;
}
return 1;
}
//用DFS求第一个顶点到最后一个顶点的最短路径
int min_dist = INFINITY;
int cur_dist = 0;
int visited[MAX_VERTEX_NUM];
void DFS(const ALgraph &G, int idx) {
int n = G.vexnum;
if (idx == n - 1) {
if (cur_dist < min_dist) min_dist = cur_dist;
return;
}
visited[idx] = 1;
ArcNode* p = G.vertices[idx].firstarc;
while (p != NULL) {
int next_idx = p->adjvex;
int weight = p->value;
if (!visited[next_idx]) {
cur_dist += weight;
DFS(G, next_idx);
cur_dist -= weight;
}
p = p->nextarc;
}
visited[idx] = 0;
}
int main(){
ALgraph G;
if(CreateDG(G)){
printf("创建成功\n");
}
else printf("创建失败\n");
for(int i=0;i<G.vexnum;i++){
visited[i]=0;
}
DFS(G,0);
printf("%d",min_dist);
return 0;
}
BFS
cpp
#include<cstdio>
#include<cstdlib>
#define MAX_VERTEX_NUM 20
#define INFINITY 0x3f3f3f3f
typedef char VertexType;
//边节点
typedef struct ArcNode{
int adjvex;
int value;
struct ArcNode* nextarc;
}ArcNode;
//顶点节点
typedef struct VNode{
VertexType data;
ArcNode* firstarc;
}VNode,adjList[MAX_VERTEX_NUM];
//构建邻接表
typedef struct ALgraph{
adjList vertices;
int vexnum,arcnum;
}ALgraph;
//返回节点的索引
int LocateVex(const ALgraph &G,VertexType e){
for(int i=0;i<G.vexnum;i++){
if(G.vertices[i].data==e){
return i;
}
}
return -1;
}
//创建图
int CreateDG(ALgraph &G){
printf("请输入顶点数和边数:\n");
scanf("%d %d",&G.vexnum,&G.arcnum);
getchar();
printf("请输入顶点的信息:\n");
for(int i=0;i<G.vexnum;i++){
scanf("%c",&G.vertices[i].data);
getchar();
G.vertices[i].firstarc=NULL;
}
printf("请输入边的关系:\n");
ArcNode* p;
VertexType V1,V2;
int v;
for(int k=0;k<G.arcnum;k++){
scanf("%c %c %d",&V1,&V2,&v);
getchar();
int i=LocateVex(G,V1);
int j=LocateVex(G,V2);
if(i==-1||j==-1){
return 0;
}
p=(ArcNode*)malloc(sizeof(ArcNode));
p->adjvex=j;
p->value=v;
p->nextarc=G.vertices[i].firstarc;
G.vertices[i].firstarc=p;
}
return 1;
}
//用BFS求第一个顶点到最后一个顶点的最短路径
typedef struct QNode{
int idx;
int path_len;//起点到路径的长度
}QNode;
int BFS(const ALgraph &G){
int n=G.vexnum;
int* dist=(int*)malloc(n*sizeof(int));
for(int i=0;i<n;i++){
dist[i]=INFINITY;
}
QNode queue[MAX_VERTEX_NUM*10];
int front=0,rear=0;
queue[rear].idx=0;
queue[rear].path_len=0;
rear++;
while(front<rear){
QNode cur=queue[front];
front++;
int cur_idx=cur.idx;
int cur_len=cur.path_len;
if(cur_len>dist[cur_idx]){
continue;
}
ArcNode* p=G.vertices[cur_idx].firstarc;
while(p!=NULL){
int next_idx=p->adjvex;
int weight=p->value;
int new_len=cur_len+weight;
if(new_len<dist[next_idx]){
dist[next_idx]=new_len;
queue[rear].idx=next_idx;
queue[rear].path_len=new_len;
rear++;
}
p=p->nextarc;
}
}
int result=dist[n-1];
free(dist);
return result;
}
int main(){
ALgraph G;
if(CreateDG(G)){
printf("创建成功\n");
}
else printf("创建失败\n");
int result=BFS(G);
printf("%d",result);
return 0;
}