实验无向图中求两点间的所有简单路径.docx
《实验无向图中求两点间的所有简单路径.docx》由会员分享,可在线阅读,更多相关《实验无向图中求两点间的所有简单路径.docx(18页珍藏版)》请在冰豆网上搜索。
![实验无向图中求两点间的所有简单路径.docx](https://file1.bdocx.com/fileroot1/2022-12/30/b745c87c-f4f0-47fb-b2db-8cdba92fa146/b745c87c-f4f0-47fb-b2db-8cdba92fa1461.gif)
实验无向图中求两点间的所有简单路径
实验6无向图中求两点间的所有简单路径
计科二班宋瑞霞20100810217
一、需求分析
1、用无向图表示高速公路网,其中顶点表示城市,边表示城市之间的高速公路。
设计一个找路程序,获取两个城市之间的所有简单路径。
2、由用户通过键盘输入:
(1)结点总数,
(2)结点的城市编号(4位长的数字,例如电话区号,长沙是0731),
(3)连接城市的高速公路(用高速公路连接的两个城市编号标记),
(4)要求取所有简单路径的两个城市编号。
不对非法输入做处理,即假设输入都是合法的。
3、输出:
将所有路径(有城市编号组成)输出到DOS界面上。
4、测试数据:
输入:
68(结点数和边数)
000100020003000400050006(结点的城市编号)
00010003(连接城市间的高速公路)
00010005
00020006
00030002
00030004
00030006
00040006
00050006
00010002(要求取所有简单路径的两个城市编号)
输出:
000100030002(两个城市间的所有简单路径)
0001000300060002
00010003000400060002
0001000500060002
00010005000600030002
000100050006000400030002
二、概要设计
抽象数据类型
根据对问题的分析,要用无向图表示高速公路网,其中顶点表示城市,边表示城市之间的高速公路。
所以要建立一个图来实现。
图的ADT设计如下:
数据元素:
包括一个顶点集合和一个边集合
数据关系:
网状关系
基本操作:
Graph(intnumvert)//构造图结构
virtualintn()=0;//获取顶点的个数
virtualintfirst(int)=0;//访问所给顶点的第一个邻居
virtualintnext(int,int)=0;//访问当前邻居的下一个邻居
virtualvoidsetedge(int,int)=0;//建立所给两顶点之间的边
virtualvoidsetmark(intv,intval)=0;//给顶点做标记
virtualintgetmark(intv)=0;//获取顶点是否已做标记
算法的基本思想
首先,根据输入的结点总数构建一个线性表,将输入的城市编号即顶点依次添加到线性表中;然后就是在图的二维数组中存入边即连接两个城市间的高速公路,这步操作首先要找到两个城市即两个顶点在线性表中的位置如m和n,然后再在二维数组相应的位置(m,n)上存入1建立该条边;最后当所有的边都存入图中后,由于深度优先的结果是沿着图的某一分支搜索直至末端,然后回溯,在沿着另一条分支搜索,依次类推,故对图进行深度优先搜索,即可得到两个城市间的简单路径。
程序的流程
程序由四个模块组成:
1、输入模块:
输入图的顶点和边;
2、构建模块:
用线性表存储顶点,用二维数组存储边,构建图结构;
3、处理模块:
对图进行深度优先搜索;
4、输出模块:
将深度优先搜索后得到的所有简单路径输出到DOS界面上。
三、详细设计
物理数据类型
该问题需要输入4位长的数字表示的城市编号,为了能够存储,采用C++语言中的字符串string来定义变量线性表中的元素类型,数组的大小为4。
根据用邻接矩阵表示法来实现图的相关知识,要先建立一个线性表来存储顶点,由于结点总数即图的顶点数已知,则线性表的长度已知,故用顺序表实现比较好,因为顺序表是预先分配一段连续的存储空间,而且没有结构性开销。
1、顺序表的具体实现如下:
template(在本问题,Elem为string)
classAlist
{
private:
intmaxSize;//顺序表的最大长度
intlistSize;//顺序表的实际长度
intfence;//指向当前位置
Elem*listArray;//存储顺序表元素的数组
public:
Alist(intsize=DefaultListSize)//构造一个由用户指定最大长度的空顺序表
{
maxSize=size;
listSize=fence=0;
listArray=newElem[maxSize];
}
boolappend(constElem&item)//添加
{
if(listSize==maxSize)
returnfalse;
else
{
listArray[listSize++]=item;
returntrue;
}
}
intrightLength()const//右边长度
{
returnlistSize-fence;
}
boolgetvalue(iElem&it)const//获取当前位置的元素值,若右边为空,返回false
{
if(rightLength()==0)
returnfalse;
else
{
it=listArray[fence];
returntrue;
}
}
voidsetStart()//将当前位置置0
{
fence=0;
}
voidnext()//右移一位
{
if(fencefence++;
}
};
2、图的具体实现如下:
classGraph
{
private:
intnumvertex,numedge;//存储顶点数和边数
int**matrix;//指向邻接矩阵的指针
int*mark;//指向访问标记数组的指针
public:
Graph(intnumvert)//实现邻接矩阵
{
inti,j;
numvertex=numvert;
numedge=0;
mark=newint[numvert];
for(i=0;imark[i]=0;
matrix=(int**)newint*[numvertex];//构造邻接矩阵
for(i=0;imatrix[i]=newint[numvertex];
for(i=0;ifor(j=0;jmatrix[i][j]=0;
}
~Graph()//析构函数
{
delete[]mark;
for(inti=0;idelete[]matrix[i];
delete[]matrix;
}
intn()//获取顶点个数
{
returnnumvertex;
}
inte()//获取边的个数
{
returnnumedge;
}
intfirst(intv)//访问所给顶点的第一个邻居
{
inti;
for(i=0;iif(matrix[v][i]!
=0)
returni;
returni;
}
intnext(intv1,intv2)//访问当前邻居的下一个邻居
{
inti;
for(i=v2+1;iif(matrix[v1][i]!
=0)
returni;
returni;
}
voidsetedge(intv1,intv2)//无向图中建立所给两顶点之间的边
{
if(matrix[v1][v2]==0)
numedge++;
matrix[v1][v2]=1;
matrix[v2][v1]=1;
}
voidsetmark(intv,intval)//给顶点做标记
{
mark[v]=val;
}
intgetmark(intv)//获取顶点是否已做标记
{
returnmark[v];
}
};
算法的具体步骤
1、定义顺序表L、图G,还有存储课程名的字符串stringcity,city1,city2,
输入顶点个数n和边数m。
2、输入顶点city并将输入的顶点依次存入顺序表L中。
for(inti=0;i{
cin>>city;
L.append(city);
}
3、输入有路连接的两个城市编号,即相互间存在边的两个顶点,找到这两个顶点在线性表中的位置,然后在图的二维数组相应的位置上存入1建立该条边。
通过一个循环将所有的边都建完,完成图的存储。
for(inti=0;i{
cin>>city1>>city2;
G.setedge(find(L,n,city1),find(L,n,city2));
}
其中find函数即实现找到顶点在线性表中的位置的功能,具体如下:
intfind(AlistL,intn,int&city)
{
inti;
stringcity1;
L.setStart();
for(i=0;i{
L.getvalue(city1);//获取当前位置的元素值
if(city1==city)//若当前位置的元素值与所要找的顶点值相同
returni;//则返回当前位置所在的位置
else
L.next();//若不同,则在向右移一位再做判断
}
}
4、对图进行深度优先搜索
intaddr[100];
intnum=-1;
voidDFS(Graph&G,intv,Alist&L,intd)
{
G.setmark(v,1);
if(v==d)
{
for(inti=0;i<=num;i++)
{
printout(L,addr[i]);
cout<<'';
}
cout<G.setmark(d,0);
num--;
return;
}
for(intw=G.first(v);wif(G.getmark(w)==0)
{
addr[++num]=w;
DFS(G,w,L,d);
}
num--;
G.setmark(v,0);
}
其中的输出函数为:
voidprintout(AlistL,intv)
{
L.setStart();
strings;
for(inti=0;iL.next();
L.getvalue(s);
cout<
}
算法的时空分析
设V为顶点数,E为边数,
(1)由于顺序表用来存储顶点,顺序队列用来存储入度为0的顶点,所以它们的空间代价都为Θ(|V|);而邻接矩阵的空间代价为Θ(|V|^2),故总的空间代价为Θ(|V|^2)。
(2)由于顺序表的添加操作的时间复杂度为Θ
(1),故将所有结点存入顺序表的时间复杂度为Θ(|V|);在对无向图进行深度优先时,DFS从两个方向处理每条边,每个顶点都必须被访问,而且只能访问一次,故总的时间复杂度为Θ(|V|+|E|)。
输入和输出的格式
输入:
请输入结点总数和边数:
//提示
等待输入
请输入城市编号:
//提示
等待输入
请输入有路连接的两个城市的编号:
//提示
等待输入
请输入要求取所有简单路径的两个城市编号:
//提示
等待输入
输出:
这两个城市间的所有简单路径为:
//提示
输出结果的位置
四、调试分析
大部分是语法错误,看着错误提示都改过来了,今天又学到点新知识,就是如果执行的界面没关的话,连接时会出现错误。
五、测试结果
六、用户使用说明
1、本程序的运行环境为DOS操作系统
2、运行程序时
提示输入结点总数和边数
城市编号
有路连接的两个城市的编号
要求取所有简单路径的两个城市编号
输出:
两个城市间的所有简单路径
七、实验心得
这次实验感觉好难啊,搞了一天的预习报告,结果就得了1分,那种感觉真的好难受的!
八、程序
#include
#include
usingnamespacestd;
#defineElemstring
classAlist
{
private:
intmaxSize;//顺序表的最大长度
intlistSize;//顺序表的实际长度
intfence;//指向当前位置
Elem*listArray;//存储顺序表元素的数组
public:
Alist(intsize)//构造一个由用户指定最大长度的空顺序表
{
maxSize=size;
listSize=fence=0;
listArray=newElem[maxSize];
}
boolappend(constElem&item)//添加
{
if(listSize==maxSize)
returnfalse;
else
{
listArray[listSize++]=item;
returntrue;
}
}
boolremove()//删除
{
Elemit;
if(rightLength()==0)
returnfalse;
it=listArray[fence];
for(inti=fence;ilistArray[i]=listArray[i+1];
listSize--;
returntrue;
}
intrightLength()const//右边长度
{
returnlistSize-fence;
}
boolgetvalue(Elem&it)const//获取当前位置的元素值,若右边为空,返回false
{
if(rightLength()==0)
returnfalse;
else
{
it=listArray[fence];
returntrue;
}
}
voidsetStart()//将当前位置置0
{
fence=0;
}
voidnext()//右移一位
{
if(fencefence++;
}
voidprev()
{
if(fence!
=0)
fence--;
}
boolsetPos(intpos)
{
if((pos>=0)&&(pos<=listSize))
fence=pos;
return(pos>=0)&&(pos<=listSize);
}
};
classGraph
{
private:
intnumvertex,numedge;
int**matrix;
int*mark;
public:
Graph(intnumvert)
{
inti,j;
numvertex=numvert;
numedge=0;
mark=newint[numvert];
for(i=0;imark[i]=0;
matrix=(int**)newint*[numvertex];
for(i=0;imatrix[i]=newint[numvertex];
for(i=0;ifor(j=0;jmatrix[i][j]=0;
}
~Graph()
{
delete[]mark;
for(inti=0;idelete[]matrix[i];
delete[]matrix;
}
intn()
{
returnnumvertex;
}
inte()
{
returnnumedge;
}
intfirst(intv)
{
inti;
for(i=0;iif(matrix[v][i]!
=0)
returni;
returni;
}
intnext(intv1,intv2)
{
inti;
for(i=v2+1;iif(matrix[v1][i]!
=0)
returni;
returni;
}
voidsetedge(intv1,intv2)
{
matrix[v1][v2]=1;
matrix[v2][v1]=1;
}
voidsetmark(intv,intval)
{
mark[v]=val;
}
intgetmark(intv)
{
returnmark[v];
}
};
intfind(AlistL,intn,strings)
{
inti;
strings1;
L.setStart();
for(i=0;i{
L.getvalue(s1);
if(s1==s)
returni;
else
L.next();
}
}
voidprintout(AlistL,intv)
{
L.setStart();
strings;
for(inti=0;iL.next();
L.getvalue(s);
cout<
}
intaddr[100];
intnum=-1;
voidDFS(Graph&G,intv,Alist&L,intd)
{
G.setmark(v,1);
if(v==d)
{
for(inti=0;i<=num;i++)
{
printout(L,addr[i]);
cout<<'';
}
cout<G.setmark(d,0);
num--;
return;
}
for(intw=G.first(v);wif(G.getmark(w)==0)
{
addr[++num]=w;
DFS(G,w,L,d);
}
num--;
G.setmark(v,0);
}
voidmain()
{
inti,n,m;
stringcity,city1,city2;
cout<<"请输入顶点数和边数:
\n";
cin>>n>>m;
GraphG(n);
AlistL(n);
cout<<"请输入城市编号:
\n";
for(i=0;i{
cin>>city;
L.append(city);
}
cout<<"请输入有路连接的两个城市的编号:
\n";
for(i=0;i{
cin>>city1>>city2;
G.setedge(find(L,n,city1),find(L,n,city2));
}
cout<<"请输入要求取所有简单路径的两个城市编号:
\n";
cin>>city1>>city2;
cout<<"这两个城市间的所有简单路径为:
\n";
addr[++num]=find(L,n,city1);
DFS(G,find(L,n,city1),L,find(L,n,city2));
}