图的遍历实验报告附C++源码.docx

上传人:b****4 文档编号:24324286 上传时间:2023-05-26 格式:DOCX 页数:13 大小:51.47KB
下载 相关 举报
图的遍历实验报告附C++源码.docx_第1页
第1页 / 共13页
图的遍历实验报告附C++源码.docx_第2页
第2页 / 共13页
图的遍历实验报告附C++源码.docx_第3页
第3页 / 共13页
图的遍历实验报告附C++源码.docx_第4页
第4页 / 共13页
图的遍历实验报告附C++源码.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

图的遍历实验报告附C++源码.docx

《图的遍历实验报告附C++源码.docx》由会员分享,可在线阅读,更多相关《图的遍历实验报告附C++源码.docx(13页珍藏版)》请在冰豆网上搜索。

图的遍历实验报告附C++源码.docx

图的遍历实验报告附C++源码

图的遍历

一、问题背景

若用有向网表示网页的链接网络,其中顶点表示某个网页,有向弧表示网页之间的链接关系。

试设计一个网络蜘蛛系统,分别以广度优先和深度优先的策略抓取网页。

二、需求分析

1)首先输入顶点的数量,然后是各顶点对应的字母,再输入各条弧(权值都置为1);

2)输出从首个顶点开始的广度优先遍历序列和深度先遍历序列;

3)为了达到任意图的遍历(结点名称不一定是数字,可以是任意可见字符),可以自定义一个数组类型,保存该结点的名称和记录是否被访问;

4)图使用相邻矩阵来实现;

5)测试数据:

输入

输入顶点数和弧数:

89

输入8个顶点.

输入顶点0:

a

输入顶点1:

b

输入顶点2:

c

输入顶点3:

d

输入顶点4:

e

输入顶点5:

f

输入顶点6:

g

输入顶点7:

h

输入9条弧.

输入弧0:

ab1

输入弧1:

bd1

输入弧2:

be1

输入弧3:

dh1

输入弧4:

eh1

输入弧5:

ac1

输入弧6:

cf1

输入弧7:

cg1

输入弧8:

fg1

输出

广度优先遍历:

abdhecfg

深度优先遍历:

abcdefgh

三、概要设计

抽象数据类型

为了遍历任意图,定义了如下数据类型,用于存储该结点的名称和记录是否被访问过。

classNode//基本抽象数据类型

{

public:

charch;//记录名称,如果将这里改成数组,结点名称可以是多个字符

intflag;//记录结点是否被访问

};

classGraph//图类,此类中,封装了图的一些成员和一些必须的成员函数

{

private:

intgetSub(char);//获取某名称的下标

Node*arrNode;//记录名称和是否访问的数组

intnumVertex,numEdge;//记录图的顶点数和边数

int**matrix;//用一个二维数组记录两点间是否相连,1相连,0断开

public:

voidsetCh(char,int);//将数组的arrNode的每一个单元设置一个结点名称

Graph(int);

~Graph();

intgetNumVertex();//获得图的顶点数

charfirst(charch);//获得相邻结点

charnext(charch1,charch2);//获得隔着ch2,但与ch2相邻的结点

voidsetEdge(char,char,intw=1);//设置两顶点的边和权重(权重默认为1)

intgetMark(char);//获取是否被访问的记录,已访问返回1,未访问返回0

voidsetMark(char);//把已访问的结点,设置标记

};

算法的基本思想

用一个自定义类型的数组,记录每个结点的信息(包括名称、是否被访问),且此数组作为图的成员变量之一;用一个类,对数组进行相应的操作,以便获得所需的信息。

深度优先采取的递归思想。

首先,将从起点,沿某条边,顺势遍历下去,直到不能继续遍历下去。

这时,又从起点的另一结点开始,遍历下去。

如此往复,知道将所有结点遍历完。

广度优先得使用队列。

首先,将起点入队,并标为已访问。

进入循环,当队列不为空时,出队,输出,并将与出队的元素相邻的且未访问的结点全部放入队列,标为已访问。

一次循环,只有一个结点出队,大于等于0个结点入队。

voidDFS(Graph*G,charch)//深度优先遍历图

{

inti=0;

cout<

G->setMark(ch);

for(charw=G->first(ch);igetNumVertex();w=G->next(ch,w))

{

if(G->getMark(w)==0)

DFS(G,w);

i++;

}

}

voidBFS(Graph*G,charch,myQueue*q)//广度优先遍历图

{

charv,w;

q->enqueue(ch);

G->setMark(ch);

while(q->length()!

=0)

{

q->dequeue(v);

cout<

inti=0;

for(w=G->first(v);igetNumVertex();w=G->next(v,w))

{

if(G->getMark(w)==0)

{

G->setMark(w);

q->enqueue(w);

}

i++;

}

}

}

程序的流程

输入顶点数、边数——>完成图的初始化——>输入顶点名称、设置边——>输入遍历起点——>深度优先遍历,输出结果——>广度优先遍历,输出结果

算法的时空分析

因为此程序追求结点的个性化(可以不按ABCD……的顺序来命名,可以用任意可见字符),使得程序的时间代价比较大。

不管是设置顶点名称,还是遍历,这都与图的顶点个数相关,包括根据结点名称获得下标的函数也是用循环实现的,时间复杂度为Θ(n)。

总之,时间开销比较大。

输入和输出的格式

输入

输入顶点数和弧数:

//提示输入

等待输入

输入8个顶点.//提示

输入顶点0:

//提示输入

等待输入

……

输入9条弧.//提示

输入弧0:

//提示输入

等待输入

四、运行截图

五、实验心得(可选)

这个实验,总的难度不大。

但我在追求结点名称的个性化的时候,没注意到这带来的时间开销,在写实验报告时才发现。

实验中,大量使用了循环,所以比较适合于密集图,稀疏图用此,那就是程序,那就是浪费时间了。

发现这个程序,还存在不完善的地方。

如果图不是连通的,那么将不能把所有的点遍历完。

六、附录(源码)

/*********************各类定义******************************/

classNode//基本抽象数据类型

{

public:

charch;//记录名称,如果将这里改成数组,结点名称可以是多个字符

intflag;//记录结点是否被访问

};

classGraph//图类,此类中,封装了图的一些成员和一些必须的成员函数

{

private:

intgetSub(char);//获取某名称的下标

Node*arrNode;//记录名称和是否访问的数组

intnumVertex,numEdge;//记录图的顶点数和边数

int**matrix;//用一个二维数组记录两点间是否相连,1相连,0断开

public:

voidsetCh(char,int);//将数组的arrNode的每一个单元设置一个结点名称

Graph(int);

~Graph();

intgetNumVertex();//获得图的顶点数

charfirst(charch);//获得相邻结点

charnext(charch1,charch2);//获得隔着ch2,但与ch2相邻的结点

voidsetEdge(char,char,intw=1);//设置两顶点的边和权重(权重默认为1)

intgetMark(char);//获取是否被访问的记录,已访问返回1,未访问返回0

voidsetMark(char);//把已访问的结点,设置标记

};

/*************各函数的函数体*****************************/

Graph:

:

Graph(intn)

{

inti,j;

arrNode=newNode[n];

numVertex=n;

numEdge=0;

for(i=0;i

arrNode[i].flag=0;

matrix=newint*[numVertex];

for(i=0;i

matrix[i]=newint[numVertex];

for(i=0;i

for(j=0;j

matrix[i][j]=0;

}

Graph:

:

~Graph()

{

delete[]arrNode;

for(inti=0;i

delete[]matrix[i];

delete[]matrix;

}

intGraph:

:

getSub(charch)//获取下标

{

for(inti=0;i

if(ch==arrNode[i].ch)

returni;

}

intGraph:

:

getNumVertex()//获取顶点数

{

returnnumVertex;

}

charGraph:

:

first(charch)//获取相邻结点

{

for(inti=0;i

if(matrix[getSub(ch)][i]!

=0)

returnarrNode[i].ch;

returnch;

}

charGraph:

:

next(charch1,charch2)//获取与ch2相邻的结点

{

for(inti=getSub(ch2)+1;i

if(matrix[getSub(ch1)][i]!

=0)

returnarrNode[i].ch;

returnch1;

}

voidGraph:

:

setEdge(charch1,charch2,intw)//设置边

{

if(matrix[getSub(ch1)][getSub(ch2)]==0)

{

numEdge++;

matrix[getSub(ch1)][getSub(ch2)]=1;

}

}

intGraph:

:

getMark(charch)//获取访问信息

{

for(inti=0;i

if(ch==arrNode[i].ch)

returnarrNode[i].flag;

return-1;

}

voidGraph:

:

setMark(charch)//设置标记

{

for(inti=0;i

if(ch==arrNode[i].ch)

arrNode[i].flag=1;

}

voidGraph:

:

setCh(charch,intn)//将结点名称设置在字符中

{

arrNode[n].ch=ch;

}

/***************主函数*********************/

voidDFS(Graph*,char);//深度优先遍历函数声明

voidBFS(Graph*,char,myQueue*);//广度优先遍历函数声明

intmain()

{

intnumVer,numE,i;

chartemp1,temp2;//temp1,temp2作临时变量,记录输入的值

myQueue*q=newmyQueue;

cout<<"输入定点数和弧数:

";

cin>>numVer>>numE;

GraphmyGraph1(numVer);

GraphmyGraph2(numVer);

cout<<"请输入"<

\n";

for(i=0;i

{

cout<<"输入顶点"<

";

cin>>temp1;

myGraph1.setCh(temp1,i);

myGraph2.setCh(temp1,i);

}

cout<<"请输入"<

\n";

for(i=0;i

{

cout<<"输入弧"<

";

cin>>temp1>>temp2;

myGraph1.setEdge(temp1,temp2);

myGraph2.setEdge(temp1,temp2);

}

cout<<"深度优先结果:

";

DFS(&myGraph1,'a');

cout<<"\n广度优先结果:

";

BFS(&myGraph2,'a',q);

cout<

return0;

}

voidDFS(Graph*G,charch)//深度优先遍历函数体

{

inti=0;

cout<

G->setMark(ch);

for(charw=G->first(ch);igetNumVertex();w=G->next(ch,w),i++)

if(G->getMark(w)==0)

DFS(G,w);

}

voidBFS(Graph*G,charch,myQueue*q)//广度优先遍历函数体

{

charv,w;

q->enqueue(ch);

G->setMark(ch);

while(q->length()!

=0)

{

q->dequeue(v);

cout<

inti=0;

for(w=G->first(v);igetNumVertex();w=G->next(v,w),i++)

if(G->getMark(w)==0)

{

G->setMark(w);

q->enqueue(w);

}

}

}

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

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1