实验5物联1301班刘悦08080112.docx

上传人:b****1 文档编号:14060248 上传时间:2023-06-20 格式:DOCX 页数:19 大小:55.68KB
下载 相关 举报
实验5物联1301班刘悦08080112.docx_第1页
第1页 / 共19页
实验5物联1301班刘悦08080112.docx_第2页
第2页 / 共19页
实验5物联1301班刘悦08080112.docx_第3页
第3页 / 共19页
实验5物联1301班刘悦08080112.docx_第4页
第4页 / 共19页
实验5物联1301班刘悦08080112.docx_第5页
第5页 / 共19页
实验5物联1301班刘悦08080112.docx_第6页
第6页 / 共19页
实验5物联1301班刘悦08080112.docx_第7页
第7页 / 共19页
实验5物联1301班刘悦08080112.docx_第8页
第8页 / 共19页
实验5物联1301班刘悦08080112.docx_第9页
第9页 / 共19页
实验5物联1301班刘悦08080112.docx_第10页
第10页 / 共19页
实验5物联1301班刘悦08080112.docx_第11页
第11页 / 共19页
实验5物联1301班刘悦08080112.docx_第12页
第12页 / 共19页
实验5物联1301班刘悦08080112.docx_第13页
第13页 / 共19页
实验5物联1301班刘悦08080112.docx_第14页
第14页 / 共19页
实验5物联1301班刘悦08080112.docx_第15页
第15页 / 共19页
实验5物联1301班刘悦08080112.docx_第16页
第16页 / 共19页
实验5物联1301班刘悦08080112.docx_第17页
第17页 / 共19页
实验5物联1301班刘悦08080112.docx_第18页
第18页 / 共19页
实验5物联1301班刘悦08080112.docx_第19页
第19页 / 共19页
亲,该文档总共19页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

实验5物联1301班刘悦08080112.docx

《实验5物联1301班刘悦08080112.docx》由会员分享,可在线阅读,更多相关《实验5物联1301班刘悦08080112.docx(19页珍藏版)》请在冰点文库上搜索。

实验5物联1301班刘悦08080112.docx

实验5物联1301班刘悦08080112

算法分析与设计实验报告

第5次实验

姓名

刘悦

学号

201308080112

班级

物联1301班

时间

12.12上午

地点

工训楼C栋309

实验名称

贪心法求最短路径

实验目的

通过上机实验,掌握贪心算法的思想,利用Dijkstra算法求解最短路径并实现。

实验原理

使用Dijkstra算法。

即每次从未遍历顶点中,选择到源结点距离最小的点。

然后更新这个点的邻接点到源结点的距离值。

重复这个步骤,直至所有的结点均被遍历。

实验步骤

1用邻接矩阵表示有向图,并进行初始化,同时选择源结点与目的结点。

2选取候选集中距离最短的顶点,把其加入终点集合。

3考虑此顶点的邻接顶点,若经过此顶点后,其邻接顶点的到达源结点的距离比原来的距离短,则修改其距离。

4重复上面的步骤,直至所有的顶点均被遍历。

关键代码

/*=================================================================

定义图类来存储图的信息。

=================================================================*/

classGraph

{

private:

intnumVertex;//图的顶点数

int**matrix;//图的边权值

int*mark;//记录顶点是否被访问

public:

//构造函数

Graph(intnumVert)

{

Init(numVert);//调用初始化函数

}

//析构函数

//删除动态分配的内存

~Graph()

{

delete[]mark;

for(inti=0;i<=numVertex;i++)

delete[]matrix[i];

delete[]matrix;

}

//初始化函数

voidInit(intn)

{

inti;

numVertex=n;

mark=newint[n+1];

//将所有结点初始化为为被访问的

for(i=0;i<=numVertex;i++)

mark[i]=UNVISITED;

//动态内存分配

matrix=(int**)newint*[numVertex+1];

for(i=0;i<=numVertex;i++)

matrix[i]=newint[numVertex+1];

//将所有边权值设为-1,表示无边相连

for(i=0;i<=numVertex;i++)

for(intj=0;j<=numVertex;j++)

matrix[i][j]=-1;

}

//求顶点数函数

intn()

{

returnnumVertex;

}

//求第一个邻接点

//求得第一个边并返回顶点编号

intfirst(intv)

{

inti;

for(i=1;i<=numVertex;i++)

if(matrix[v][i]!

=-1)//有边相连

returni;

returni;

}

//求下一个邻接点

//求得某个结点的下一个邻接点并返回顶点编号

intnext(intv,intw)

{

inti;

//因为当前邻接点为w,求下一个的话就是从w+1开始

for(i=w+1;i<=numVertex;i++)

if(matrix[v][i]!

=-1)//有边相连

returni;

returni;

}

//设置边的权值的函数

voidsetEdge(intv1,intv2,intwt)

{

matrix[v1][v2]=wt;//将结点v1和结点v2之间的边权值设为wt

}

//查看某个边的权值

intweight(intv1,intv2)

{

returnmatrix[v1][v2];//结点v1和结点v2之间的边权值

}

//查看某个结点是否被访问过

intgetMark(intv)

{

returnmark[v];//返回结点v的mark值

}

//设置某个结点的标志,即是否被访问过

voidsetMark(intv,intval)

{

mark[v]=val;//将结点v的标志设为val

}

};

/*=================================================================

minVertex返回当前到起点距离最小的未被访问的结点。

思路:

首先按顺序找到一个未被遍历的结点;

然后将此结点与后面的结点比较,找到距离最小的结点。

*******************************************************************

D数组表示到源结点的距离。

D[i]表示结点i到源结点的距离。

=================================================================*/

intminVertex(Graph&G,int*D)

{

inti;

intv=0;

for(i=1;i<=G.n();i++)

//找第一个未被访问的结点

if(G.getMark(i)==UNVISITED)

{

v=i;

break;

}

for(i++;i<=G.n();i++)

{

//找距源结点距离最小的未被访问的顶点

if(G.getMark(i)==UNVISITED&&((((D[i]

=-1)||(D[v]==-1))))

v=i;

}

returnv;

}

 

/*=================================================================

Dijkstra函数找到当前结点的邻接点,并更新其边权值和祖先节点。

其中记录祖先结点为方便找到路径。

*******************************************************************

pre数组记录结点的祖先结点。

pre[i]表示结点i的祖先结点。

D数组表示到源结点的距离。

D[i]表示结点i到源结点的距离。

=================================================================*/

voidDijkstra(Graph&G,int*D,ints,int*pre)

{

inti,v,w;

for(i=1;i<=G.n();i++)

{

//调用minVertex函数,找到未被访问的距离最小的结点

v=minVertex(G,D);

//如果返回的为-1就表示所有结点均被访问过,结束。

if(D[v]==-1)

return;

//将找到的结点置为已访问

G.setMark(v,VISITED);

//寻找结点的邻接点更新到起点的距离和祖先结点

for(w=G.first(v);w<=G.n();w=G.next(v,w))

if((D[w]>(D[v]+G.weight(v,w)))||(D[w]==-1))

{

D[w]=D[v]+G.weight(v,w);//更新到起点的距离

pre[w]=v;//更新祖先结点

}

}

}

测试结果

可以看到实现了最短路径与最短路径长度的输出。

在我们给定的这个图中使用最短路径算法即Dijkstra算法的时候时间很短,可以看到算法的性质很好。

实验心得

这个Dijkstra算法真的是学烂了,加起来学了4遍多了。

所以对算法的思想还是比较了解的,但是代码编写起来还是有各种问题。

还记得上学期第一次学Dijkstra算法的时候,就要做实验写代码,那个时候三个人一个组,然后都花了很久的时间才搞定了一个结构体实现的代码。

这次的实现,我选择使用类来实现,与结构体比起来有一个优势就是,结构体实现需要定义两个结构体,另外还需要些很多函数。

使用类的话就只用写一个类,然后将函数都写在类里面。

虽然使用类和结构体实现不同,但是其大致思路和代码都差不多。

但是这个类的实现代码我却写了很久,可能是一开始的时候没有厘清思路,各种初始化没弄好,就一直中断。

但是改到最后才发现,其实是因为最主要的一个问题没处理好,就是传递的参数,因为我的图传递的时候没有使用指针,所以就有一个问题,就是在每个函数里对图进行的修改没有办法在调用它的函数中看见,所以一直出现问题,最后一个小小的&符号解决了所有的问题。

其实一开始的实现是只能输出最短路径的长度,不能输出最短路径是什么的。

但是后来增加了几个数组之后就实现了输出最短路径。

这个也要在理解算法思想的基础下才好实现。

只要增加数组来记录是哪个结点到当前结点的,即祖先结点。

这样进行反向寻找就可以找到路径输出了。

通过这次实验,我更加熟练的掌握了Dijkstra算法,相信经过这么多次Dijkstra算法的学习与代码的编写,以后一定可以熟练使用Dijkstra算法。

 

实验得分

助教签名

附录:

完整代码

 

#include

#include

#include

#include

#include

#defineUNVISITED0

#defineVISITED1

usingnamespacestd;

/*============================================================================

定义图类来存储图的信息。

============================================================================*/

classGraph

{

private:

intnumVertex;//图的顶点数

int**matrix;//图的边权值

int*mark;//记录顶点是否被访问

public:

//构造函数

Graph(intnumVert)

{

Init(numVert);

}

//析构函数

//删除动态分配的内存

~Graph()

{

delete[]mark;

for(inti=0;i<=numVertex;i++)

delete[]matrix[i];

delete[]matrix;

}

//初始化函数

voidInit(intn)

{

inti;

numVertex=n;

mark=newint[n+1];

//将所有结点初始化为为被访问的

for(i=0;i<=numVertex;i++)

mark[i]=UNVISITED;

//动态内存分配

matrix=(int**)newint*[numVertex+1];

for(i=0;i<=numVertex;i++)

matrix[i]=newint[numVertex+1];

//将所有边权值设为-1,表示无边相连

for(i=0;i<=numVertex;i++)

for(intj=0;j<=numVertex;j++)

matrix[i][j]=-1;

}

//求顶点数函数

intn()

{

returnnumVertex;

}

//求第一个邻接点

//求得第一个边并返回顶点编号

intfirst(intv)

{

inti;

for(i=1;i<=numVertex;i++)

if(matrix[v][i]!

=-1)//有边相连

returni;

returni;

}

//求下一个邻接点

//求得某个结点的下一个邻接点并返回顶点编号

intnext(intv,intw)

{

inti;

//因为当前邻接点为w,求下一个的话就是从w+1开始

for(i=w+1;i<=numVertex;i++)

if(matrix[v][i]!

=-1)//有边相连

returni;

returni;

}

//设置边的权值的函数

voidsetEdge(intv1,intv2,intwt)

{

matrix[v1][v2]=wt;//将结点v1和结点v2之间的边权值设为wt

}

//查看某个边的权值

intweight(intv1,intv2)

{

returnmatrix[v1][v2];//结点v1和结点v2之间的边权值

}

//查看某个结点是否被访问过

intgetMark(intv)

{

returnmark[v];//返回结点v的mark值

}

//设置某个结点的标志,即是否被访问过

voidsetMark(intv,intval)

{

mark[v]=val;//将结点v的标志设为val

}

};

intminVertex(Graph&G,int*D);

voidDijkstra(Graph&G,int*D,ints,int*pre);

/*============================================================================

main函数是主函数。

构造出给定的图的邻接矩阵。

进行一些必要的初始化。

之后调用Dijkstra函数,求出最短路径长度,得到记录路径的pre数组。

根据pre数组,求出最短路径。

找出到终点的路径,存储在trave_pre数组中。

因为trave_pre数组中存储的为倒序的路径,所以反向输出即为路径。

============================================================================*/

intmain()

{

cout<<"================================"<

cout<<"==============START============="<

cout<<"================================"<

GraphG(10);

intD[11];

intpre[11];

inttrave_pre[11];

inti,j;

intstart_node;

intend_node;

//各点至起点的距离初始化为-1

for(i=0;i<=G.n();i++)

{

D[i]=-1;

pre[i]=0;

trave_pre[i]=0;

}

//有边相连的更新其边值

G.setEdge(1,2,4);G.setEdge(1,3,2);G.setEdge(1,4,5);

pre[2]=1;pre[3]=1;pre[4]=1;

G.setEdge(2,5,7);G.setEdge(2,6,5);

G.setEdge(3,6,9);

G.setEdge(4,5,2);G.setEdge(4,7,7);

G.setEdge(5,8,4);

G.setEdge(6,10,6);

G.setEdge(7,9,3);

G.setEdge(8,10,7);

G.setEdge(9,10,8);

//求每个结点的祖先结点

for(intk=1;k<=G.n();k++)

{

for(intm=1;m<=G.n();m++)

if((G.weight(k,m)

=-1)

pre[m]=k;

}

//输入起点

cout<<"请输入起点:

";

cin>>start_node;

//将起点置为已访问

G.setMark(start_node,VISITED);

//输入终点

cout<<"请输入终点:

";

cin>>end_node;

//更新到起点的距离D值

for(intk=1;k<=G.n();k++)

D[k]=G.weight(start_node,k);

//开始计时

clock_tstart,end,over;

start=clock();

end=clock();

over=end-start;

start=clock();

//调用函数

Dijkstra(G,D,start_node,pre);

//结束计时

end=clock();

cout<<"================================"<

cout<<"============输出结果============"<

cout<<"================================"<

//输出路径:

cout<<"路径为:

"<

//将找出到终点的路径,存储在trave_pre数组中

for(intt=1,i=end_node;(pre[i]!

=0);i=pre[i])

{

trave_pre[t]=pre[i];

t++;

}

//因为trave_pre数组中存储的为倒序的路径,所以反向输出即为路径

for(intt=G.n();t>=1;t--)

{

if(trave_pre[t]!

=0)

cout<";

}

//输出终点

cout<

//输出最短路径多长

cout<<"最短路径为:

"<

//输出时间

printf("Thetimeis%6.3f\n",(double)(end-start-over)/CLK_TCK);

cout<

cout<<"================================"<

cout<<"===============END=============="<

cout<<"================================"<

return0;

}

/*============================================================================

minVertex返回当前到起点距离最小的未被访问的结点。

思路:

首先按顺序找到一个未被遍历的结点;

然后将此结点与后面的结点比较,找到距离最小的结点。

******************************************************************************

D数组表示到源结点的距离。

D[i]表示结点i到源结点的距离。

============================================================================*/

intminVertex(Graph&G,int*D)

{

inti;

intv=0;

for(i=1;i<=G.n();i++)

//找第一个未被访问的结点

if(G.getMark(i)==UNVISITED)

{

v=i;

break;

}

for(i++;i<=G.n();i++)

{

//找距源结点距离最小的未被访问的顶点

if(G.getMark(i)==UNVISITED&&((((D[i]

=-1)||(D[v]==-1))))

v=i;

}

returnv;

}

/*============================================================================

Dijkstra函数找到当前结点的邻接点,并更新其边权值和祖先节点。

其中记录祖先结点为方便找到路径。

******************************************************************************

pre数组记录结点的祖先结点。

pre[i]表示结点i的祖先结点。

D数组表示到源结点的距离。

D[i]表示结点i到源结点的距离。

============================================================================*/

voidDijkstra(Graph&G,int*D,ints,int*pre)

{

inti,v,w;

for(i=1;i<=G.n();i++)

{

//调用minVertex函数,找到未被访问的距离最小的结点

v=minVertex(G,D);

//如果返回的为-1就表示所有结点均被访问过,结束。

if(D[v]==-1)

return;

//将找到的结点置为已访问

G.setMark(v,VISITED);

//寻找结点的邻接点更新到起点的距离和祖先结点

for(

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 医药卫生 > 基础医学

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2