南邮数据结构上机实验三图的基本运算及飞机换乘次数最少问题.docx
《南邮数据结构上机实验三图的基本运算及飞机换乘次数最少问题.docx》由会员分享,可在线阅读,更多相关《南邮数据结构上机实验三图的基本运算及飞机换乘次数最少问题.docx(33页珍藏版)》请在冰豆网上搜索。
![南邮数据结构上机实验三图的基本运算及飞机换乘次数最少问题.docx](https://file1.bdocx.com/fileroot1/2023-1/9/8e3d169e-d8b9-4a71-8c11-8f3bb5c08153/8e3d169e-d8b9-4a71-8c11-8f3bb5c081531.gif)
南邮数据结构上机实验三图的基本运算及飞机换乘次数最少问题
实验报告
(2015/2016学年第二学期)
课程名称
数据结构A
实验名称
图的基本运算及飞机换乘次数最少问题
实验时间
2016
年
5
月
19
日
指导单位
计算机科学与技术系
指导教师
骆健
学生姓名
班级学号
学院(系)
管理学院
专业
信息管理与信息系统
实习题名:
图的基本运算
班级姓名学号日期2016.05.19
一、问题描述
验证教材中关于在邻接矩阵和邻接表两种不同的储存结构上实现图的基本运算的算法(见程序9.1~程序9.8),在邻接矩阵存储结构上实现图的深度和广度优先遍历算法,设计主函数,测试上述运算。
二、概要设计
文件graph.cpp中在该文件中定义图数据结构的抽象模板类Graph。
邻接矩阵类MGraph是从抽象类Graph派生得来,邻接表类LGraph也是从抽象类Graph派生得来。
主函数的代码如图所示。
三、详细设计
1.类和类的层次设计
程序定义了Graph类,以及邻接矩阵类MGraph和邻接表类LGraph以及循环列表类SeqQueue。
邻接矩阵类MGraph继承了Graph的数据成员n和e,重载了Graph的纯虚函数。
保护数据成员T**a指向动态生成的二维数组,用以存储邻接矩阵。
邻接表类LGraph也继承了Graph的数据成员n和e及重载了Graph的纯虚函数,边结点由类ENode定义,每个结点有三个域adjVex、w和nextArc。
邻接表的表头组成为一维数组,a是指向该数组的指针。
(a)循环队列类
(b)模版类Graph,MGraph和LGraph
2.核心算法
深度优先搜索用栈来实现:
1)把根节点压入栈中
2)每次从栈中弹出一个元素,搜索所有在它下一级的元素,把这些元素压入栈中。
并把这个元素记为它下一级元素的前驱
3)找到所要找的元素时结束程序
4)如果遍历整个树还没有找到,结束程序
广度优先搜索使用队列来实现:
1)把根节点放到队列的末尾
2)每次从队列的头部取出一个元素,查看这个元素所有的下一级元素,把它们放到队列的末尾。
并把这个元素记为它下一级元素的前驱
3)找到所要找的元素时结束程序
4)如果遍历整个树还没有找到,结束程序
DFS()
BFS()
四、程序代码
template
voidMGraph:
:
DFS()//深度遍历
{
bool*visited=newbool[n];
for(inti=0;ivisited[i]=false;
for(i=0;iif(!
visited[i])
DFS(i,visited);
delete[]visited;
}
template
voidMGraph:
:
DFS(intv,bool*visited)
{
visited[v]=true;
cout<<""<for(inti=0;iif(a[v][i]!
=noEdge&&a[v][i]!
=0&&!
visited[i])
DFS(i,visited);
}
template
voidMGraph:
:
BFS()//广度遍历
{
bool*visited=newbool[n];
for(inti=0;ivisited[i]=false;
for(i=0;iif(!
visited[i])
BFS(i,visited);
delete[]visited;
}
template
voidMGraph:
:
BFS(intv,bool*visited)
{
SeqQueueq(n);
visited[v]=true;
cout<<""<q.EnQueue(v);
while(!
q.IsEmpty())
{
q.Front(v);
q.DeQueue();
for(inti=0;iif(a[v][i]!
=noEdge&&a[v][i]!
=0&&!
visited[i])
{
visited[i]=true;
cout<<""<
q.EnQueue(i);
}
}
}
五、测试和调试
1.测试用例和结果
测试结果如下图
1)输入元素的个数以及权值
2)输入边以及权值
3)得到图的深度遍历以及广度遍历
4)输入要搜索的边,得到搜索结果
5)输入要删除的边,得到新的遍历
2.
结果分析
1)程序能够正确的实现关于在邻接矩阵和邻接表两种不同的储存结构上实现图的基本运算的算法,在邻接矩阵存储结构上实现图的深度和广度优先遍历算法
2)由测试结果来看,若在输出数据时以图的形式输出,更简单直观,程序还有待改进。
实习题名:
飞机最少换乘问题
班级姓名学号日期2016.05.19
一、问题描述
设有n个城市,编号为0~n−1,m条航线的起点和终点由用户输入提供。
寻找一条换乘次数最少的线路方案。
(提示:
可以使用有向图表示城市间的航线。
只要两城市间有航班,则图中这两点间存在一条权为1的边。
可以使用Dijkstra算法实现)
二、概要设计
文件min.cpp中定义了两个类,分别是图数据结构的抽象模板类Graph以及从抽象类Graph派生得来邻接矩阵类MGraph。
主函数mian的代码如图所示:
三、详细设计
1.类和类的层次结构
程序定义了Graph类,以及邻接矩阵类MGraph。
同上邻接矩阵类MGraph也继承了Graph的数据成员n和e,重载了Graph的纯虚函数。
保护数据成员T**a指向动态生成的二维数组,用以存储邻接矩阵。
模版类Graph和MGraph
2.核心算法
定义了类之后,求换乘次数最少主要是通过迪杰斯特拉算法实现。
迪杰斯特拉算法主要通过动态创建数据结构,初始化操作,将源点v加入集合S,使用for循环,按照长度的非递减次序,依次产生n-1条最短路径等步骤实现。
核心算法程图如下:
Dijkstra()
四、程序代码
template
voidMGraph:
:
Dijkstra(intv,T*d,int*path)//迪杰斯特拉算法
{
inti,k,w;
if(v<0||v>n-1)
throwOutOfBounds;
bool*s=newbool[n];
for(i=0;i{
s[i]=false;
d[i]=a[v][i];
if(i!
=v&&d[i]path[i]=v;
else
path[i]=-1;
}
s[v]=true;
d[v]=0;
for(i=1;i{
k=Choose(d,s);
s[k]=true;
for(w=0;wif(!
s[w]&&(d[k]+a[k][w]){
d[w]=d[k]+a[k][w];
path[w]=k;
}
}
}
五、测试和调试
1.测试用例和结果
1)输入城市个数以及航线条数
2)分别输入每条航线的起点和终点
3)得到换乘次数最小的路线
4)最后输入N退出
2.结果分析
1)程序能够完全实现题目的要求,通过迪杰斯特拉算法实现了飞机换乘次数最小的路线
2)下一步的目标是使用类似的算法对城市公交车的最少换乘问题进行解决
实习小结
在本次实验中出现了一些问题在用邻接矩阵存储结构实现图的广度优先遍历时,出现了输出结果为有序排列,改变图的顶点之间的关系后结果仍然不变,修改约束条件后,问题得以解决。
在用邻接表存储结构实现Djikstra算法时,出现了指针访问冲突的问题,经调试检查发现是由访问数组越界导致,修改了约束条件后问题得以解决。
本次实验主要是要求在邻接表存储结构上实现图的深度优先遍历以及广度优先遍历和使用Djikstra算法求单源最短路径的问题。
经过本次实验对图的不同存储结构适用情况有了更进一步认识,通过修改Djikstra算法使其实现在图的邻接表存储结构上求最短路径,进一步加深对该算法的理解。
通过这次实验我对图这种应用广泛的数据结构更加熟悉,结合课堂知识,以及老师的帮助,让我学到了更多。
附录:
1.图的基本运算
#include
constintINFTY=2147483640;
enumResultCode{Underflow,Duplicate,Failure,Success,NotPresent};
template
classGraph//抽象类
{
public:
virtualResultCodeInsert(intu,intv,T&w)=0;
virtualResultCodeRemove(intu,intv)=0;
virtualboolExist(intu,intv)const=0;
protected:
intn,e;
};
template//循环队列类
classSeqQueue
{
public:
SeqQueue(intmSize);
~SeqQueue(){delete[]q;}
boolIsEmpty()const{returnfront==rear;}
boolIsFull()const{return(rear+1)%maxSize==front;}
boolFront(T&x)const;
boolEnQueue(Tx);
boolDeQueue();
voidClear(){front=rear=0;}
private:
intfront,rear;
intmaxSize;
T*q;
};
template
SeqQueue:
:
SeqQueue(intmSize)//构造函数
{
maxSize=mSize;
q=newT[maxSize];
front=rear=0;
}
template
boolSeqQueue:
:
Front(T&x)const//取队头元素
{
if(IsEmpty())
{
returnfalse;
}
x=q[(front+1)%maxSize];
returntrue;
}
template
boolSeqQueue:
:
EnQueue(Tx)//在队尾插入x
{
if(IsFull())
{
cout<<"Full"<returnfalse;
}
q[rear=(rear+1)%maxSize]=x;
returntrue;
}
template
boolSeqQueue:
:
DeQueue()//删除队头元素
{
if(IsEmpty())
{
cout<<"Underflow"<returnfalse;
}
front=(front+1)%maxSize;
returntrue;
}
template
classMGraph:
publicGraph//邻接矩阵类
{
public:
MGraph(intmSize,constT&noedg);
~MGraph();
ResultCodeInsert(intu,intv,T&w);
ResultCodeRemove(intu,intv);
boolExist(intu,intv)const;
voidDFS();
voidBFS();
protected:
T**a;
TnoEdge;
voidDFS(intv,bool*visited);
voidBFS(intv,bool*visited);
};
template
MGraph:
:
MGraph(intmSize,constT&noedg)//构造函数
{
n=mSize;
e=0;
noEdge=noedg;
a=newT*[n];
for(inti=0;i{
a[i]=newT[n];
for(intj=0;ja[i][j]=noEdge;
a[i][i]=0;
}
}
template
MGraph:
:
~MGraph()//析构函数
{
for(inti=0;idelete[]a[i];
delete[]a;
}
template
ResultCodeMGraph:
:
Insert(intu,intv,T&w)//插入函数
{
if(u<0||v<0||u>n-1||v>n-1||u==v)
returnFailure;
if(a[u][v]!
=noEdge)
returnDuplicate;
a[u][v]=w;
e++;
returnSuccess;
}
template
ResultCodeMGraph:
:
Remove(intu,intv)//删除函数
{
if(u<0||v<0||u>n-1||v>n-1||u==v)
returnFailure;
if(a[u][v]==noEdge)
returnNotPresent;
a[u][v]=noEdge;
e--;
returnSuccess;
}
template
boolMGraph:
:
Exist(intu,intv)const//判断边是否存在
{
if(u<0||v<0||u>n-1||v>n-1||u==v||a[u][v]==noEdge)
returnfalse;
returntrue;
}
template
voidMGraph:
:
DFS()//深度遍历
{
bool*visited=newbool[n];
for(inti=0;ivisited[i]=false;
for(i=0;iif(!
visited[i])
DFS(i,visited);
delete[]visited;
}
template
voidMGraph:
:
DFS(intv,bool*visited)
{
visited[v]=true;
cout<<""<for(inti=0;iif(a[v][i]!
=noEdge&&a[v][i]!
=0&&!
visited[i])
DFS(i,visited);
}
template
voidMGraph:
:
BFS()//广度遍历
{
bool*visited=newbool[n];
for(inti=0;ivisited[i]=false;
for(i=0;iif(!
visited[i])
BFS(i,visited);
delete[]visited;
}
template
voidMGraph:
:
BFS(intv,bool*visited)
{
SeqQueueq(n);
visited[v]=true;
cout<<""<q.EnQueue(v);
while(!
q.IsEmpty())
{
q.Front(v);
q.DeQueue();
for(inti=0;iif(a[v][i]!
=noEdge&&a[v][i]!
=0&&!
visited[i])
{
visited[i]=true;
cout<<""<
q.EnQueue(i);
}
}
}
template//结点类
classENode
{
public:
ENode(){nextArc=NULL;}
ENode(intvertex,Tweight,ENode*next)
{
adjVex=vertex;
w=weight;
nextArc=next;
}
intadjVex;
Tw;
ENode*nextArc;
};
template
classLGraph:
publicGraph//邻接表类
{
public:
LGraph(intmSize);
~LGraph();
ResultCodeInsert(intu,intv,T&w);
ResultCodeRemove(intu,intv);
boolExist(intu,intv)const;
protected:
ENode**a;
};
template
LGraph:
:
LGraph(intmSize)//构造函数
{
n=mSize;
e=0;
a=newENode*[n];
for(inti=0;ia[i]=NULL;
}
template
LGraph:
:
~LGraph()//析构
{
ENode*p,*q;
for(inti=0;i{
p=a[i];
q=p;
while(p)
{
p=p->nextArc;
deleteq;
q=p;
}
}
delete[]a;
}
template
boolLGraph:
:
Exist(intu,intv)const//判断边是否存在
{
if(u<0||v<0||u>n-1||v>n-1||u==v)
returnfalse;
ENode*p=a[u];
while(p&&p->adjVex!
=v)
p=p->nextArc;
if(!
p)
returnfalse;
elsereturntrue;
}
template
ResultCodeLGraph:
:
Insert(intu,intv,T&w)//插入
{
if(u<0||v<0||u>n-1||v>n-1||u==v)
returnFailure;
if(Exist(u,v))
returnDuplicate;
ENode*p=newENode(v,w,a[u]);
a[u]=p;
e++;
returnSuccess;
}
template
ResultCodeLGraph:
:
Remove(intu,intv)//删除
{
if(u<0||v<0||u>n-1||v>n-1||u==v)
returnFailure;
ENode*p=a[u],*q;
q=NULL;
while(p&&p->adjVex!
=v)
{
q=p;
p=p->nextArc;
}
if(!
p)
returnNotPresent;
if(q)
q->nextArc=p->nextArc;
else
a[u]=p->nextArc;
deletep;
e--;
returnSuccess;
}
intmain()//主函数
{
intn,g;
cout<<"请输入元素的个数:
";
cin>>n;
MGraphA(n,INFTY);
LGraphB(n);
cout<<"请输入边的条数:
";
cin>>g;
int*a=newint[g];
int*b=newint[g];
int*w=newint[g];
for(inti=0;i{
cout<<"请输入边及权值:
";
cin>>a[i]>>b[i]>>w[i];
A.Insert(a[i],b[i],w[i]);
B.Insert(a[i],b[i],w[i]);
}
cout<<"该图的深度优先遍历为:
"<A.DFS();
cout<cout<<"该图的广度优先遍历为:
"<A.BFS();
cout<cout<<"请输入要搜索的边:
";
intc,d;
cin>>c>>d;
if(A.Exist(c,d))
cout<<"邻接矩阵中该边存在!
"<else
cout<<"邻接矩阵中该边不存在!
"<if(B.Exist(c,d))
cout<<"邻接表中该边存在!
"<else
cout<<"邻接表中该边不存在!
"<cout<<"请输入要删除的边:
";
inte,f;
cin>>e>>f;
if(A.Remove(e,f)==Success)
cout<<"邻接矩阵中删除该边成功!
"<elseif(A.Remove(e,f)==NotPresent)
cout<<"邻接矩阵中该边不存在!
"<else
cout<<"输入错误!
"<if(B.Remove(e,f)==Success)
cout<<"邻接表中删除该边成功!
"<elseif(B.Remove(e,f)==NotPresent)
cout<<"邻接表中该边不存在!
"<else
cout<<"邻接表中输入