数据结构实验六简单路径.docx
《数据结构实验六简单路径.docx》由会员分享,可在线阅读,更多相关《数据结构实验六简单路径.docx(25页珍藏版)》请在冰豆网上搜索。
数据结构实验六简单路径
HUNANUNIVERSITY
课程实验报告
题目:
简单路径
学生姓名
学生学号
专业班级
指导老师李晓鸿
完成日期2015年12月12日
一、需求分析
1.程序的功能
该程序可以通过构建一个图用来表示各个城市之间是否有高速公路连通的关系,可以实现查询两城市间所有路径的功能,如果存在路径则输出。
2.输入的形式
本程序要求用户首先输入一个结点总数,然后输入结点的城市编号,最后输入要查询所有简单路径的两座城市的名称。
当用户输入不合法时,提示用户输入有误,并重新输入。
输入具体格式如下:
请输入城市总数:
n(大于零的整数)
请输入输入城市1名称:
请输入输入城市2名称:
请输入输入城市3名称:
......
请输入输入城市n名称:
请输入城市间的高速公路:
请输入两所城市的名称:
3.输出的形式
①若有路径
从城市A到城市B的所有路径如下:
//路径1
//路径2
②若无路径
两城市不连通
4.测试数据
①.正常的输入:
请输入城市总数:
4
请输入输入城市1名称:
0001
请输入输入城市2名称:
0002
请输入输入城市3名称:
0003
请输入输入城市4名称:
0004
请输入城市间的高速公路:
00010002
请输入城市间的高速公路:
00020003
请输入城市间的高速公路:
00030004
请输入城市间的高速公路:
00010004
请输入城市间的高速公路:
00
请输入两所城市的名称:
00010004
输出:
两城市间的路径为:
0001000200030004
两城市间的路径为:
00010004
②.正常的输入:
请输入城市总数:
5
请输入输入城市1名称:
c1
请输入输入城市2名称:
c2
请输入输入城市3名称:
c3
请输入输入城市4名称:
c4
请输入输入城市5名称:
c5
请输入城市间的高速公路:
c1c2
请输入城市间的高速公路:
c1c5
请输入城市间的高速公路:
c5c4
请输入城市间的高速公路:
c4c3
请输入城市间的高速公路:
00
请输入两所城市的名称:
c2c4
输出:
两城市间的路径为:
c2c1c5c4
③.无路径情况:
请输入城市总数:
3
请输入输入城市1名称:
a
请输入输入城市2名称:
b
请输入输入城市3名称:
c
请输入城市间的高速公路:
ab
请输入城市间的高速公路:
00
请输入两所城市的名称:
ac
输出:
两城市不连通
④.错误的城市个数
请输入城市总数:
-1
输入错误重新输入(大于零的整数)
请输入城市总数2
请输入输入城市1名称:
1
请输入输入城市2名称:
2
请输入城市间的高速公路:
12
请输入城市间的高速公路:
00
请输入两所城市的名称:
12
输出:
两城市的路径为12
⑤.存在自返路径
请输入城市总数:
2
请输入输入城市1名称:
上海
请输入输入城市2名称:
长沙
请输入城市间的高速公路:
上海上海
请输入城市间的高速公路:
上海长沙
请输入两所城市的名称:
长沙上海
输出:
长沙上海
二、概要设计
1.抽象数据类型
因为各个结点之间是网状结构,那么一个结点会和多个结点连接,因此我们使用图来存储各个结点的信息。
同时我们需要一个数据结构来搜索图,该数据结构满足先进后出,所以使用栈来实现。
2.ADT
ADTStack{
数据对象:
D={ai|ai∈binNode,i=1,2,...,n,n≥0
数据关系:
R1={|ai-1,ai∈D,i=2,...,n}
约定an端为栈顶,a1端为栈底。
若栈中没有元素,则为空栈。
基本操作:
boolpush(constBinNode&item);
boolpop(BinNode&it);
booltopValue(BinNode&it);
intlength();const;}
ADTGraph{
数据对象:
V,R(图是由一个顶点集V和一个弧集R构成的数据结构)
数据关系:
Graph=(V,R)VR={|v,w∈V且P(v,w)}
基本操作:
intn()=0;//返回图节点数
inte()=0;//返回图边数
intfirst(int)=0;//返回该节点的第一条邻边
voidsetEdge(intv1,intv2)//加边
intnext(int,int)=0;//返回下一条邻边
intgetMark(int)=0;//有标记吗
voidsetMark(int,int)=0;//设置标记}
3.算法的基本思想
使用深度优先搜索DFS对图进行遍历,在搜索过程中,每当访问一个顶点V后,DFS就会递归的访问它的所有未被访问的相邻顶点。
即先访问点v,把所有与v相关联的边存入栈,弹出栈顶元素,栈顶元素代表的边所关联的另一个顶点就是就是要访问的下一个元素,重复对v的操作;依次类推直到所有元素都被处理完毕。
4程序流程
程序主要由四个步骤组成:
(1) 输入城市总数
(2) 输入正确的城市编号列表
(3) 输入所有的有高速公路直接连接的城市对编号
(4) 循环输入需要寻找路径的城市对的编号寻找它们之间的所有简单路径。
三.详细设计
1.物理数据类型
由于边数目未知,所以对于遍历图的时间效率并不清楚,所以可以用邻接表或者邻接矩阵来实现,本实验中使用邻接矩阵。
栈元素未知,用链表来实现栈。
用string保存输入的城市名信息。
2.算法的具体步骤
图的构建——路径的存储——深度优先搜索——栈元素的打印
图的构建:
创建一个城市数n*城市数n的二阶矩阵,并且给每一个元素赋值为零。
Graph(intnumVert)
{
inti,j;
numVertex=numVert;
numEdge=0;
mark=newPoint[numVert];//Initializemarkarray
for(i=0;imark[i].ViMark=-1;
matrix=(int**)newint*[numVertex];//Makematrix
for(i=0;imatrix[i]=newint[numVertex];
for(i=0;ifor(intj=0;j}
路径的存储:
将城市v1到城市v2在矩阵中对应的坐标(v1,v2)赋值为1。
void setEdge(int v1, int v2)
{
if (matrix[v1][v2] == 0)
numEdge++;
matrix[v1][v2] = 1;
}
深度优先搜索:
在搜索过程中,每当访问一个顶点V后,DFS就会递归的访问它的所有未被访问的相邻顶点。
即先访问点v,把所有与v相关联的边存入栈,弹出栈顶元素,栈顶元素代表的边所关联的另一个顶点就是就是要访问的下一个元素,重复对v的操作;当弹出栈的元素就是我们需要到达的城市v2时,输出整个栈的元素,再将v2的值设置为-1,表示为未访问状态,将v2弹出栈,重复对v的操作;依次类推直到所有元素都被处理完毕。
voidDFS(Graph*G,intv1,intorigin,intv2,AStack&b,intM[100][100],intD[100],int&count)
{
stringCh;
b.push(G->getVal(v1));
intv;
G->setMark(v1,1);
if(G->getVal(v1)==G->getVal(v2))
{
for(inti=0;in();i++)
for(intj=0;jn();j++)
G->setEdge(i,j,M[i][j]);//将路径进栈
cout<<"两城间的路径为:
";
b.print();
cout<b.pop(Ch);//即城市v2出栈
G->setMark(v2,-1);//将v2标记为未被访问
count++;//路线多一条
return;
}
for(intw=G->first(v1);wn();w=G->next(v1,w))//访问v1所有顶点
{
G->setEdge(w,v1,0);
if(G->getMark(w)==-1||w==5)
{
DFS(G,w,origin,v2,b,M,D,count);
}
}
b.pop(Ch);
G->Find(Ch,v);
G->setMark(v,-1);
}
栈所有元素的打印:
新建一个和需要打印栈a长度相同的栈b,栈a中每一个元素依次出栈进入栈b,直到栈a为空,栈b依次出栈,并且输出每一个元素的值,同时将这些元素进栈a,直到栈b为空。
voidprint()
{
stringCh;
AStackb(length());
while(pop(Ch))
{
b.push(Ch);
}
while(b.pop(Ch))
{
cout<push(Ch);
}
}
3.算法的时空分析及改进设想
因为图的邻接矩阵是一个|V|×|V|矩阵,所以邻接矩阵的空间代价为Θ(|V|^2),对于有n个顶点的和E条弧的无向图而言,DFS对每条边分别沿两个方向进行处理,且每个顶点必须被访问一次,所以总的时间代价为Θ(|V|+|E|)。
综上可知,该程序的时间复杂度为Max(Θ(|V|^2),Θ(|V|+|E|))。
4.输入和输出的格式
①.条件的输入
请输入城市总数:
n(大于零的整数)
请输入输入城市1名称:
请输入输入城市2名称:
请输入输入城市3名称:
......
请输入输入城市n名称:
请输入城市间的高速公路:
请输入两所城市的名称:
cout<<"请输入城市总数:
";
cin>>n;
if(n<=0)
{
cout<<"输入错误重新输入(大于零的整数)"<cout<<"请输入城市总数:
";
cin>>n;
}
Grapha(n);
for(inti=0;i{
cout<<"请输入城市"<
";
cin>>Ch;
a.setVal(i,Ch);
}
cout<<"请输入城市之间的高速公路(输入两个0结束输入):
";
cin>>Ch1;
cin>>Ch2;
while(Ch1!
="0")
{
a.Find(Ch1,v1);
a.Find(Ch2,v2);
a.setEdge(v1,v2,10);
a.setEdge(v2,v1,10);
cout<<"请输入城市之间的公路:
";
cin>>Ch1;
cin>>Ch2;
}
②.输入要查找的城市
cout<<"请输入要查找的两个城市:
";
cin>>Ch1>>Ch2;
③.连通情况路径的输出(即上述算法中的栈元素的打印)
voidprint()
{
stringCh;
AStackb(length());
while(pop(Ch))
{
b.push(Ch);
}
while(b.pop(Ch))
{
cout<push(Ch);
}
}
④.不连通时的输出
if(count==0)
{
cout<<"两个城市不连通"<}
4.测试结果
①.正常的输入:
②.正常的输入:
③.无路径情况:
④.错误的城市个数
⑤.存在自返路径
#include
#include
#include
#include
usingnamespacestd;
classAStack
{
private:
intsize;//栈的大小
inttop;//栈中元素的多少
string*listArray;
public:
AStack(intsz=0)//构建栈
{
size=sz;
top=0;
listArray=newstring[sz];
}
~AStack()//销毁栈
{
delete[]listArray;
}
boolpush(conststring&item)//压栈
{
if(top==size)returnfalse;//如果栈已满则returnfalse
else
{
listArray[top++]=item;
returntrue;
}
}
boolpop(string&it)//出栈
{
if(top==0)returnfalse;//如果栈为空栈,则returnfalse
else
{
it=listArray[--top];
returntrue;
}
}
intlength()const//获取栈的长度
{
returntop;
}
voidprint()
{
stringCh;
AStackb(length());
while(pop(Ch))
{
b.push(Ch);
}
while(b.pop(Ch))
{
cout<push(Ch);
}
}
};
classPoint
{
public:
stringLessonName;
intViMark;
};
classGraph
{//Implementadjacencymatrix
private:
intnumVertex,numEdge;//Storenumberofverticesedges
int**matrix;//Pointertoadjacencymatrix
Point*mark;//Pointertomarkarray
public:
Graph(intnumVert)
{//Makegraphw/numVertvertices
inti,j;
numVertex=numVert;
numEdge=0;
mark=newPoint[numVert];//Initializemarkarray
for(i=0;imark[i].ViMark=-1;
matrix=(int**)newint*[numVertex];//Makematrix
for(i=0;imatrix[i]=newint[numVertex];
for(i=0;ifor(intj=0;j}
~Graph()
{
delete[]mark;
for(inti=0;idelete[]matrix[i];
delete[]matrix;
}
intn()
{
returnnumVertex;
}
inte()
{
returnnumEdge;
}
intfirst(intv)
{//Returnv'sfirstneighbor
inti;
for(i=0;iif(matrix[v][i]!
=0&&mark[i].ViMark==-1)returni;
returni;//Returnnifnone
}
intnext(intv1,intv2)
{
//Getv1'sneighborafterv2
inti;
for(i=v2+1;iif(matrix[v1][i]!
=0&&mark[i].ViMark==-1)
{
//cout<<"此时next的i值是:
"<returni;
}
returni;
}
//Setedge(v1,v2)towgt
voidsetEdge(intv1,intv2,intwgt)
{
if(matrix[v1][v2]==0)numEdge++;
matrix[v1][v2]=wgt;
}
voiddelEdge(intv1,intv2)
{//Deleteedge(v1,v2)
if(matrix[v1][v2]!
=0)
numEdge--;
matrix[v1][v2]=0;
}
intweight(intv1,intv2)
{
returnmatrix[v1][v2];
}
stringgetVal(intv)
{
returnmark[v].LessonName;
}
intgetMark(intv)
{
returnmark[v].ViMark;
}
voidsetVal(intv,stringval)
{
mark[v].LessonName=val;
}
voidsetMark(intv,intMark)
{
mark[v].ViMark=Mark;
}
voidFind(stringsearch,int&v)
{
for(inti=0;i{
if(mark[i].LessonName==search)
{
v=i;
return;
}
}
cout<<"路径错误"<return;
}
};
voidDFS(Graph*G,intv1,intv2,AStack&b,int&count)
{
stringCh;
b.push(G->getVal(v1));//将v1边进栈
intv;
G->setMark(v1,1);
if(G->getVal(v1)==G->getVal(v2))//已经连通的情况
{
cout<<"两城间的路径为:
";
b.print();
cout<b.pop(Ch);//即城市v2出栈
G->setMark(v2,-1);//将v2标记为未被访问
count++;//路线多一条
return;
}
for(intw=G->first(v1);wn();w=G->next(v1,w))//访问v1所有边
{
G->setEdge(w,v1,0);//访问后G图中此条路径变为0
if(G->getMark(w)==-1)
{
DFS(G,w,v2,b,count);//访问v1的下一条路径
}
}
b.pop(Ch);//出栈并且将v1边的值给ch
G->Find(Ch,v);//找到v对应的边
G->setMark(v,-1);//设置为未访问
}
intmain()
{
intn;
intv1;
intv2;
stringCh;
stringCh1;
stringCh2;
intcount=0;
cout<<"请输入城市总数:
";
cin>>n;
if(n<=0)
{
cout<<"输入错误重新输入(大于零的整数)"<cout<<"请输入城市总数:
";
cin>>n;
}
Grapha(n);
for(inti=0;i{
cout<<"请输入城市"<
";
cin>>Ch;
a.setVal(i,Ch);
}
cout<<"请输入城市之间的高速公路(输入两个0结束输入):
";
cin>>Ch1;
cin>>Ch2;
while(Ch1!
="0")
{
a.Find(Ch1,v1);
a.Find(Ch2,v2);
a.setEdge(v1,v2,1);
a.setEdge(v2,v1,1);
cout<<"请输入城市之间的公路:
";
cin>>Ch1;
cin>>Ch2;
}
cout<<"请输入要查找的两个城市:
";
cin>>Ch1>>Ch2;
a.Find(Ch1,v1);
a.Find(Ch2,v2);
AStackb(n);
DFS(&a,v1,v2,b,count);//图a查找城市v1查找城市v2栈b
if(count==0)
{
cout<<"两个城市不连通"<}
system("pause");
return0;
}