实验目的:熟悉图的基本概念、逻辑特性、存储表示方法、基本操作和基本应用。
实验要求:熟悉图的基本概念、逻辑特性、存储表示方法,实现无向网的存储表示、图的深度优先搜索遍历、广度优先搜索遍历、单源最短路径算法。
实验内容
编写程序,实现以下功能:
(1) 实现交通网、通信网或局域网的邻接矩阵存储表示,设数据元素类型为字符串(如地名、房间号等)。
(2) 实现该网的深度和广度优先搜索遍历,输出遍历结果。
#include <iostream>
using namespace std;
//邻接矩阵
const int MaxSize = 10; //图中最多顶点个数
int visited[MaxSize] = {0}; //全局数组变量visited初始化
class MGraph
{
public:
MGraph (string a[], int n, int e); //构造函数
~MGraph(){} //析构函数为空
void DFTraverse(int v); //深度优先遍历图
void BFTraverse(int v); //广度优先遍历图
private:
string vertex[MaxSize]; //存放图中顶点的数组
int edge[MaxSize][MaxSize]; //存放图中边的数组
int vertexNum, edgeNum; //图的顶点数和边数
};
//构造函数——图的建立
MGraph::MGraph(string a[], int n, int e)
{
int i, j, k;
vertexNum = n;
edgeNum = e;
for(i = 0; i < vertexNum; i++){ //存储顶点
vertex[i] = a[i];
}
for(i = 0; i < vertexNum; i++){ //初始化邻接矩阵
for(j = 0; j < vertexNum; j++){
edge[i][j] = 0;
}
}
for(k = 0; k < edgeNum; k++){ //依次输入每一条边
cin >> i >> j;
edge[i][j] = edge[j][i] = 1; //置有边标志
}
}
//深度优先遍历
void MGraph::DFTraverse(int v)
{
cout << vertex[v] << " ";
visited[v] = 1;
for(int j = 0; j < vertexNum; j++){
if(edge[v][j] == 1 && visited[j] == 0)
DFTraverse(j);
}
}
//广度优先遍历
void MGraph::BFTraverse(int v)
{
int w, j, Q[MaxSize]; //采用顺序队列
int front = -1, rear = -1; //初始化队列
cout << vertex[v] << " ";
visited[v] = 1;
Q[++rear] = v; //被访问顶点入队
while(front != rear) //当队列非空时
{
w = Q[++front]; //将队头元素出队并送到v中
for(j = 0; j < vertexNum; j++){
if(edge[w][j] == 1 && visited[j] == 0){
cout << vertex[j] << " ";
visited[j] = 1;
Q[++rear] = j;
}
}
}
}
int main()
{
int i;
string str[] = {"v0","v1","v2","v3"};
MGraph MG(str, 4, 4); //建立一个具有4个顶点4条边的无向图
for(i = 0; i < MaxSize; i++){
visited[i] = 0;
}
cout << "深度遍历序列是:";
MG.DFTraverse(0); //从顶点0出发进行深度优先遍历
cout << endl;
for(i = 0; i < MaxSize; i++){
visited[i] = 0;
}
cout << "广度遍历序列是:";
MG.BFTraverse(0); //从顶点0出发进行广度优先遍历
cout << endl;
return 0;
}
(3) *实现上述网络的邻接表存储表示,实现其广度优先搜索遍历,输出遍历结果。
#include <iostream>
using namespace std;
const int MaxSize = 10; //图中最多顶点个数
int visited[MaxSize] = {0}; //全局数组变量visited初始化
//邻接表的存储结构
struct EdgeNode //定义边表结点
{
int adjvex; //邻接点域
EdgeNode * next;
};
struct VertexNode //定义顶点表结点
{
string vertex;
EdgeNode * firstEdge;
};
//邻接表的实现
class ALGraph
{
public:
ALGraph (string a[], int n, int e); //构造函数
~ALGraph(); //析构函数
void DFTraverse(int v); //深度优先遍历图
void BFTraverse(int v); //广度优先遍历图
private:
VertexNode adjlist[MaxSize]; //存放顶点表的数组
int vertexNum, edgeNum; //图的顶点数和边数
};
//构造函数——图的建立
ALGraph::ALGraph(string a[], int n, int e)
{
int i, j, k;
EdgeNode * s = NULL;
vertexNum = n;
edgeNum = e;
for(i = 0; i < vertexNum; i++){ //输入顶点信息,初始化顶点表
adjlist[i].vertex = a[i];
adjlist[i].firstEdge = NULL;
}
for(k = 0; k < edgeNum; k++){ //依次输入每一条边
cin >> i >> j; //输入边所依附的两个顶点的编号
s = new EdgeNode; s->adjvex = j;//生成一个边表结点s
s->next = adjlist[i].firstEdge; //将结点s插入表头
adjlist[i].firstEdge = s;
}
}
//析构函数——图的销毁
ALGraph:: ~ALGraph()
{
EdgeNode * p = NULL, * q = NULL;
for(int i = 0; i < vertexNum; i++){
p = q = adjlist[i].firstEdge;
while(p != NULL){
p = p->next;
delete q;
q = p;
}
}
}
//深度优先遍历
void ALGraph::DFTraverse(int v)
{
int j;
EdgeNode * p = NULL;
cout << adjlist[v].vertex << " ";
visited[v] = 1;
p = adjlist[v].firstEdge; //工作指针p指向顶点v的边表
while(p != NULL) //依次搜索顶点v的邻接点j
{
j = p->adjvex;
if(visited[j] == 0) DFTraverse(j);
p = p->next;
}
}
//广度优先遍历
void ALGraph::BFTraverse(int v)
{
int w, j, Q[MaxSize]; //采用顺序队列
int front = -1, rear = -1; //初始化队列
EdgeNode * p = NULL;
cout <<adjlist[v].vertex <<" ";
visited[v] = 1;
Q[++rear] = v; //被访问顶点入队
while(front != rear) //当队列非空时
{
w = Q[++front]; //将队头元素出队并送到v中
p = adjlist[w].firstEdge;//工作指针p指向顶点v的边表
while(p != NULL)
{
j = p->adjvex;
if (visited[j] == 0) {
cout << adjlist[j].vertex << " ";
visited[j] = 1;
Q[++rear] = j;
}
p = p->next;
}
}
}
int main( )
{
//测试数据是图6-20(a),边是(0 1)(0 3)(0 4)(1 2)(2 4)(3 2)(3 4)
string str[] = {"v0", "v1", "v2", "v3", "v4"};
int i;
ALGraph ALG(str, 5, 7); //建立具有5个顶点7条边的有向图
for (i = 0; i < MaxSize; i++)
visited[i] = 0;
cout << "深度优先遍历序列是:";
ALG.DFTraverse(0); //从顶点0出发进行深度优先遍历
cout << endl;
for (i = 0; i < MaxSize; i++)
visited[i] = 0;
cout << "广度优先遍历序列是:";
ALG.BFTraverse(0); //从顶点0出发进行广度优先遍历
cout << endl;
return 0;
}
(4) *求从一个地点到其它各个地点的最短路径。
#include <iostream>
#define Max 503
#define INF 0xcffffff
using namespace std;
typedef struct AMGraph //定义图
{
int vex, arc;
int arcs[Max][Max]; //邻接矩阵
};
int dis[Max], path[Max]; //dis保存最短路径总权值、path通过保存路径的前驱结点来保存路径
bool book[Max]; //已找到最短路集合
void Dijkstra(AMGraph &G) //迪杰斯特拉算法
{
for (int i = 1; i <= G.vex; i++)
{
dis[i] = G.arcs[1][i]; //初始化dis数组
path[i] = dis[i] < INF ? 1 : -1; //初始化路径数组
}
book[1] = true;
dis[1] = 0; //起点初始化
for (int i = 2; i <= G.vex; i++) //遍历G.vex-1次
{
int mins = INF, u = 1;
for (int j = 1; j <= G.vex; j++) //找到当前没加入集合的最短路的后驱点
{
if (!book[j] && mins > dis[j])
{
mins = dis[j];
u = j;
}
}
book[u] = true; //将该点加入集合
for (int j = 1; j <= G.vex; j++) //遍历所有其他点对其最短路进行更新(松弛操作)
{
if (!book[j] && dis[j] > dis[u] + G.arcs[u][j])
{
dis[j] = dis[u] + G.arcs[u][j]; //更新最短路径值
path[j] = u; //修改j的前驱为u
}
}
}
}
void find(int x) //递归输出最短路径
{
if (path[x] == 1)
{
cout << 1;
}
else
{
find(path[x]);
}
cout << " -> " << x;
return;
}
void putin(AMGraph &G) //输入图
{
cin >> G.vex >> G.arc;
for (int i = 1; i <= G.vex; i++) //初始化邻接矩阵
for (int j = 1; j <= G.vex; j++)
G.arcs[i][j] = INF;
for (int i = 1; i <= G.arc; i++)
{
int u, v, w;
cin >> u >> v >> w;
G.arcs[u][v] = w;
}
}
void putout(AMGraph &G) //输出
{
/* cout << "起点 v1 到各点的最短路程为: \n";
for (int i = 1; i < G.vex; i++)
{
cout << dis[i] << " ";
}
cout << dis[G.vex] << endl; */
for (int i = 2; i <= G.vex; i++)
{
cout << "起点 v1 到 v" << i << " 的路径为: ";
find(i);
cout << " 最短路径长度为:" << dis[i] << " ";
cout << endl;
}
}
int main()
{
AMGraph G;
putin(G);
Dijkstra(G);
putout(G);
return 0;
}