1.实验目的
(1)掌握图的邻接矩阵和邻接表存储方式;
(2)掌握图的遍历算法;
(3)掌握图的实际应用——最短路径算法。
2.实验内容
(1)采用邻接矩阵/邻接表建立图;
(2)采用深度优先/广度优先搜索方式遍历图;
(3)编程实现Dijkstra最短路径算法。
3.实验步骤
- 编写代码,采用邻接表法建立有向图:
(1)输入总边数、总点数;
(2)依次输入点的信息存入顶点表,使每个表头结点的指针域初始化为NULL;
(3)创建邻接表,依次输入每条边依附的两个顶点,以及边的权值,确定这两个定点的序号i和j后,将边结点分别插入v_i和v_j对应的两个边链表的头部。 - 编写代码,实现深度优先搜索方式遍历图:
(1)从图中某个顶点v出发,访问v,并设置visited[v]的值为true;
(2)依次检查v的所有邻接点w,如果visited[w]的值为false,再从w出发进行递归遍历,直到图中所有顶点都被访问过。 - 编程实现Dijkstra最短路径算法。
(1)初始化最短路径数组D,将其赋值为最大值10000;
(2)如果v0与vi之间有弧,则将他们的权值赋给D[i];
(3)初始化数组S,将源点v0加到S中,即S[v0] = true;
(4)选择下一条最短路径的终点vk,令S[k]=true;
(5)根据条件更新从v0到其他顶点的最短路径的长度,若D[k]+p->info<D[p->adjvex],则令D[p->adjvex] = D[k]+p->info。
4.实验代码
#include <iostream>
#include <iomanip>
using namespace std;
#define MVNum 100
bool visited[100] = {false};
//有向图的邻接表存储表示 95
typedef int OtherInfo;
typedef char VerTexType;
//边结点
typedef struct ArcNode
{
int adjvex; //该边指向的顶点的位置
struct ArcNode *nextarc; //指向下一条边的指针
OtherInfo info; //权值
}ArcNode;
//顶点信息
typedef struct VNode
{
VerTexType data; //顶点的值
ArcNode *firstarc; //指向第一条依附该顶点的边的指针
}VNode,AdjList[MVNum];
//邻接表
typedef struct
{
AdjList vertices;
int vexnum,arcnum; //图的顶点数,边数
}ALGraph;
//确定定点u在图中的位置
int LocateVex(ALGraph G,VerTexType u);
//创建有向图
void CreateDG(ALGraph &G);
//深度优先遍历
void DFS_AL(ALGraph G,int v);
//Dijkstra算法
void ShortestPath_DIJ(ALGraph G,int v0);
int main()
{
int v0;
VerTexType data;
ALGraph G;
CreateDG(G);
cout << "请输入v0的值:" ;
cin >> data;
v0 = LocateVex(G,data);
cout << "深度优先遍历后得到的顶点顺序为:";
DFS_AL(G,v0);
cout << endl;
cout << "请输入v0的值:" ;
cin >> data;
v0 = LocateVex(G,data);
ShortestPath_DIJ(G,v0);
return 0;
}
int LocateVex(ALGraph G,VerTexType u)
{
//若G中存在顶点u,则返回该顶点的位置,否则返回-1.
for(int i=0;i<G.vexnum;++i)
if(u == G.vertices[i].data)
return i;
return -1;
}
void CreateDG(ALGraph &G)
{
VerTexType v1,v2;
OtherInfo otherInfo;
//VerTexType ch[8] = "abcdefg";
//VerTexType ch1[12] = "aaabcceffgd";
//VerTexType ch2[12] = "bcdeefggdbg";
//OtherInfo oi[11] = {15,2,12,6,8,4,9,10,5,4,3};
int j,k;
cout << "请输入图的总边数,总点数:";
cin >> G.arcnum >> G.vexnum;
//G.arcnum = 11;
//G.vexnum = 7;
cout << "请输入顶点的值:";
//表头结点
for(int i=0;i<G.vexnum;++i)
{
//G.vertices[i].data = ch[i];
cin >> G.vertices[i].data;
G.vertices[i].firstarc = NULL;
}
cout << "请输入一条边依附的两个顶点以及边的权值:";
//边结点
for(int i=0;i<G.arcnum;++i)
{
cin >> v1 >> v2 >> otherInfo;
//v1 = ch1[i];v2 = ch2[i];otherInfo = oi[i];
j = LocateVex(G,v1);
k = LocateVex(G,v2);
ArcNode* p1 = new ArcNode;
p1->adjvex = k;
p1->info = otherInfo;
p1->nextarc = G.vertices[j].firstarc;
G.vertices[j].firstarc = p1;
}
}
void DFS_AL(ALGraph G,int v)
{
int w;
cout << v << ":" << G.vertices[v].data << " ";
visited[v] = true;
ArcNode* p = G.vertices[v].firstarc;
while(p != NULL)
{
w = p->adjvex;
if(!visited[w])
DFS_AL(G,w);
p = p->nextarc;
}
}
void ShortestPath_DIJ(ALGraph G,int v0)
{
int n = G.vexnum,k;
bool S[n] = {false};
OtherInfo D[n],Min;
int Path[n];
ArcNode* p;
//初始化最短路径的值
for(int v=0;v<n;++v)
D[v] = 10000;
p = G.vertices[v0].firstarc;
//将与v0相关联的边的权值赋给D[]
while(p != NULL)
{
D[p->adjvex] = p->info;
p = p->nextarc;
}
S[v0] = true; //将v0加入终点集
Path[0] = v0; //记录最短路径
D[v0] = 0;
for(int v=1;v<n;++v)
{
Min = 10000;
//寻找最小值
for(int w=0;w<n;++w)
{
if(!S[w] && D[w]<Min)
{
k = w;
Min = D[w];
}
}
S[k] = true;
Path[v] = k;
p = G.vertices[k].firstarc;
while(p != NULL)
{
if(!S[p->adjvex] && D[k]+p->info<D[p->adjvex])
D[p->adjvex] = D[k]+p->info;
p = p->nextarc;
}
}
for(int i=1;i<n;i++)
{
cout << "终点集为:";
for(int j=0;j<=i;j++)
cout << G.vertices[Path[j]].data;
cout << setw(15) << "最短路径值为:" << D[Path[i]] << endl;
}
}
5.实验总结
(1)邻接矩阵法适合建立稠密图;邻接表法适合建立稀疏图。
(2)深度优先搜索遍历类似于树的先序遍历,借助于栈结构来实现递归;广度优先搜索遍历类似于树的层次遍历,借助于队列结构来实现。
(3)Dijkstra算法求最短路径求解过程是,按照路径长度递增的次序产生最短路径,时间复杂度是O(n^2)。
数据结构核心原理与算法应用