图的基本操作与实现.docx

上传人:b****3 文档编号:4226779 上传时间:2022-11-28 格式:DOCX 页数:31 大小:96.69KB
下载 相关 举报
图的基本操作与实现.docx_第1页
第1页 / 共31页
图的基本操作与实现.docx_第2页
第2页 / 共31页
图的基本操作与实现.docx_第3页
第3页 / 共31页
图的基本操作与实现.docx_第4页
第4页 / 共31页
图的基本操作与实现.docx_第5页
第5页 / 共31页
点击查看更多>>
下载资源
资源描述

图的基本操作与实现.docx

《图的基本操作与实现.docx》由会员分享,可在线阅读,更多相关《图的基本操作与实现.docx(31页珍藏版)》请在冰豆网上搜索。

图的基本操作与实现.docx

图的基本操作与实现

摘要:

图(Graph)是一种非线性结构,它的每一个顶点可以与多个其它顶点相关联,各顶点之间的关系是任意的。

这种结构的灵活性很强,可以用来描述和求解更多的实际问题,因此得到广泛的应用。

最典型的应用领域有电路分析、寻找最短路线、项目规划、鉴别化合物、统计力学、遗传学、控制论、语言学,以及一些社会科学中。

反过来,也正是由于其限制很少,已不再属于线性结构,因此运用这类结构时需要有更多的技巧。

本课题是在VC++环境下,运用图的性质完成各种基本操作的实现。

关键词:

邻接矩阵;邻接表;深度(广度)优先遍历;连通分量;递归

 

 

1需求分析

1.1课程设计题目

(1)自选存储结构,输入含n个顶点(用字符表示顶点)和e条边的图G;

(2)求每个顶点的度,输出结果;

(3)指定任意顶点x为初始顶点,对图G作DFS遍历,输出DFS顶点序列(提示:

使用一个栈实现DFS);

(4)指定任意顶点x为初始顶点,对图G作BFS遍历,输出BFS顶点序列(提示:

使用一个队列实现BFS);

(5)输入顶点x,查找图G:

若存在含x的顶点,则删除该结点及与之相关连的边,并作DFS遍历(执行操作3);否则输出信息“无x”;

(6)判断图G是否是连通图,输出信息“YES”/“NO”;

(7)如果选用的存储结构是邻接矩阵,则用邻接矩阵的信息生成图G的邻接表,即复制图G,然再执行操作

(2);反之亦然。

1.2课程设计任务及要求

1.搜集图方面的资料;

2.负责设计数据结构,画好流程图,编写代码;

3.撰写课程设计报告;

4.参加答辩。

1.3课程设计思想

1.3.1图的邻接表表示

在第i行的单链表中,各结点分别存放与同一个顶点vi关联的各条边。

各结点配有标识dest,指示该边的另一个顶点;还配有指针link,指向同一链表中的下一条边的边结点。

对于带权图,结点中还要保存该边的权值cost。

通过在顶点表的第i个顶点信息中保存的指针adj,可以找到与顶点i对应的边链表的第一个边结点;此外,该记录还保存有该顶点的其他信息。

1.3.2图的深度优先搜索

深度优先搜索是个不断探查和回溯的过程。

在探查的每一步,算法都有一个当前顶点。

最初的当前顶点,也就是指定的起始顶点。

每一步探查过程中,首先对当前顶点v进行访问,并立即设置该顶点的访问标志visited[v]=true。

接着在v的所有邻接顶点中,找出尚未访问过的一个,将其作为下一步探查的当前顶点。

倘若当前顶点的所有邻接顶点都已经被访问过,则退回一步,将前一步所访问的顶点重新取出,当作探查的当前顶点。

重复上述过程,直到最初指定起始顶点的所有邻接顶点都被访问到,此时连通图中的所有顶点也必然都被访问过了。

1.3.3图的广度优先搜索

广度优先搜索时一个逐层遍历的过程,在此过程中,图中有多少顶点就要重复多少步。

每一步都有一个当前顶点。

最初的当前顶点是主过程指定的起始顶点。

在每一步中,首先访问当前顶点v,并设置该顶点的访问标志visited[v]=true。

接着依次访问v的各个未曾被访问过的邻接顶点w1,w2,…,wt,然后再顺序访问w1,w2,…,wt的所有还未被访问过的邻接顶点。

再从这些访问过的顶点出发,再访问它们的所有还未被访问过的邻接顶点,如此做下去,直到图中所有顶点都被访问为止。

2概要设计

2.1程序的整体功能结构

输入1个图先求出每个顶点的度,输出结果;然后指定任意顶点x为初始顶点,对图G作DFS遍历,输出DFS顶点序列;接着指定任意顶点x为初始顶点,对图G作BFS遍历,输出BFS顶点序列;其次输入顶点x,查找图G:

若存在含x的顶点,则删除该结点及与之相关连的边,并作DFS遍历(执行操作3);否则输出信息“无x”;下一步是判断图G是否是连通图,输出信息“YES”/“NO”;最后如果选用的存储结构是邻接矩阵,则用邻接矩阵的信息生成图G的邻接表,即复制图G,然再执行操作

(2);反之亦然。

2.2数据结构的设计

2.2.1边节点类的定义

structEdge//边结点的定义

{

intdest;//边的另一顶点位置

Ecost;//边上的权值

Edge*link;//下一条边链指针

};

2.2.2顶点类的定义

template//顶点的定义

structVertex

{

Tdata;//顶点的名字

Edge*adj;//边链表的头指针

};

2.2.3图类的定义

template

classGraph//图的类定义

{

protected:

intmaxVertices;//图中最大的顶点数

intnumEdges;//当前边数

intnumVertices;//当前顶点数

T*output;//存放遍历的数组

T*input;//存放输入数组

Vertex*NodeTable;//顶点表(各边链表的头结点)

intgetVertexPos(constTvertx)//取顶点v在数组中的位置

{

intj=-1;

for(inti=0;i

{

if(NodeTable[i].data==vertx)

j=i;

}

returnj;

}

voidDFS(Graph&G,intv,boolvisited[])//图的深度优先搜索

{

cout<

visited[v]=true;//作访问标记

intw=G.getFirstNeighbor(v);//第一个邻接顶点

while(w!

=-1)//若邻接顶点w存在

{

if(!

visited[w])

DFS(G,w,visited);//若w未访问过,递归访问顶点w

w=G.getNextNeighbor(v,w);//下一个邻接顶点

}

}

public:

Graph();//构造函数

~Graph();//析构函数

TgetValue(inti)//取顶点i的值

{

return(i>=0&&i

NodeTable[i].data:

0;

}

boolinsertVertex(constT&vertex);//插入顶点vertex

boolinsertEdge(intv1,intv2,Ecost);//插入边(v1,v2),权值为cost

boolremoveVertex(intv);//删除指定的顶点

boolremoveEdge(intv1,intv2);//删除一条边

intgetFirstNeighbor(intv);//取顶点v的第一个邻接顶点

intgetNextNeighbor(intv,intw);//取v的邻接顶点w的下一邻接顶点

intgetFirstCost(intv);//取顶点v的第一个邻接顶点的cost值

intgetNextCost(intv,intw);//取v的邻接顶点w的下一邻接顶点的cost值

voidDFS(Graph&G,constT&v);//从顶点v出发对图G进行深度优先遍历的主过程

intBFS(Graph&G,constT&v);//图的广度优先搜索

voidWheCan(Graph&G);//判断是否为连通图

voidOutPut();//输出

voidHaveEdge(Graph&G);//求顶点的度

voidSerachVertex(Graph&G);//输入顶点x,查找图G:

若存在含x的顶点,则删除该结点及与之相关连的边,并作DFS遍历

voidChangeGraph(Graph&G);//将用邻接表表示的数转换为邻接矩阵表示

voidInput();//输入

};

3详细设计和实现

3.1算法流程图

程序主要设计了六个功能:

首先是求每个顶点的度,然后可以选择对图G作DFS(或BFS)搜索,接着可以判断此图是否连通,接着可以将图G转换为临街矩阵存储方式退出,最后可以对图G作查找顶点。

主函数流程如下:

图3.1.1主函数流程图

3.2各个要求的实现方法

3.2.1自选存储结构,输入含n个顶点(用字符表示顶点)和e条边的图G

采用邻接表的存储结构

N个顶点的输入存储到顶点节点链表(Vertex)中

如果第n个节点和第m个节点之间含有一条边e,就将n和m的顶点链表中指向的边链表中存储入n和m在顶点表中的下标和权值

3.2.2求每个顶点的度,输出结果

顶点的度指与该顶点相关联的边的条数

在用邻接链表做为图的存储方式中,要求一个顶点n的度只要去搜索存放顶点n的边节点链表,其中存放了多少条边的信息,这个顶点的度就为多少。

3.2.3指定任意顶点x为初始顶点,对图G作DFS遍历,输出DFS顶点序列

DFS遍历指的是深度优先搜索

深度优先搜索的基本思想:

DFS在访问图中某一起始顶点v后,由v出发,访问它的任一邻接顶点w1;再从w1出发,访问与w1邻接但还没有访问过的顶点w2;然后再从w2出发,进行类似的访问,…如此进行下去,直至到达所有的邻接顶点都被访问过的顶点u为止。

接着,退回一步,退到前一次刚访问过的顶点,看是否还有其它没有被访问的邻接顶点。

如果有,则访问此顶点,之后再从此顶点出发,进行与前述类似的访问;如果没有,就再退回一步进行搜索。

重复上述过程,直到连通图中所有顶点都被访问过为止。

3.2.4指定任意顶点x为初始顶点,对图G作BFS遍历,输出BFS顶点序列

BFS指的是广度优先搜索

BFS基本思想:

BFS在访问了起始顶点v之后,由v出发,依次访问v的各个未被访问过的邻接顶点w1,w2,…,wt,然后再顺序访问w1,w2,…,wt的所有还未被访问过的邻接顶点。

再从这些访问过的顶点出发,再访问它们的所有还未被访问过的邻接顶点,…如此做下去,直到图中所有顶点都被访问到为止。

广度优先搜索是一种分层的搜索过程,每向前走一步可能访问一批顶点,不像深度优先搜索那样有往回退的情况。

因此,广度优先搜索不是一个递归的过程。

3.2.5输入顶点x,查找图G:

若存在含x的顶点,则删除该结点及与之相关连的边,并作DFS遍历(执行操作3);否则输出信息“无x”;

输入顶点,在顶点表中所搜是否含有这个顶点,如果没有,就输出“无x”。

如果含有,搜索存放顶点n的边节点链表,找出其中存放的顶点m,然后将这个顶点m链表中的存放n的那个节点删除,同时将n中存放m的节点删除。

然后在顶点链表中存放顶点n的节点删除。

3.2.6判断图G是否是连通图,输出信息“YES”/“NO”;

对图做BFS遍历,如果遍历到的顶点数等于当前的顶点数的个数,这个图就是联通图,反之就不是连通图

3.2.7如果选用的存储结构是邻接矩阵,则用邻接矩阵的信息生成图G的邻接表,即复制图G,然再执行操作

(2);反之亦然

我采用的是邻接矩阵做为图的存储结构。

将用邻接表存储的图转化为邻接矩阵的存储的基本思想是:

(1)将图的顶点表中存放的顶点的信息都存放在一个顶点矩阵中

(2)逐个搜索各个顶点的边节点链表,如果含有节点,将邻接矩阵中对应二维数组的值赋值为cost的值。

顶点的度为:

统计第i行(列)不为0的个数可得顶点i的度。

3.3主程序设计

///////////////////////////////////////////////////Graph.h

#include

#include

#include"Queue.h"

usingnamespacestd;

template

structEdge//边结点的定义

{

intdest;//边的另一顶点位置

Ecost;//边上的权值

Edge*link;//下一条边链指针

Edge(){}//构造函数

Edge(intnum,Ecost):

dest(num),weight(cost),link(NULL){}//构造函数

booloperator!

=(Edge&R)const//判边等否

{

returndest!

=R.dest;

}

};

template//顶点的定义

structVertex

{

Tdata;//顶点的名字

Edge*adj;//边链表的头指针

};

template

classGraph//图的类定义

{

protected:

intmaxVertices;//图中最大的顶点数

intnumEdges;//当前边数

intnumVertices;//当前顶点数

T*output;//存放遍历的数组

T*input;//存放输入数组

Vertex*NodeTable;//顶点表(各边链表的头结点)

intgetVertexPos(constTvertx)//取顶点v在数组中的位置

{

intj=-1;

for(inti=0;i

{

if(NodeTable[i].data==vertx)

j=i;

}

returnj;

}

voidDFS(Graph&G,intv,boolvisited[])//图的深度优先搜索

{

cout<

visited[v]=true;//作访问标记

intw=G.getFirstNeighbor(v);//第一个邻接顶点

while(w!

=-1)//若邻接顶点w存在

{

if(!

visited[w])

DFS(G,w,visited);//若w未访问过,递归访问顶点w

w=G.getNextNeighbor(v,w);//下一个邻接顶点

}

}

public:

Graph();//构造函数

~Graph();//析构函数

TgetValue(inti)//取顶点i的值

{

return(i>=0&&i

NodeTable[i].data:

0;

}

boolinsertVertex(constT&vertex);//插入顶点vertex

boolinsertEdge(intv1,intv2,Ecost);//插入边(v1,v2),权值为cost

boolremoveVertex(intv);//删除指定的顶点

boolremoveEdge(intv1,intv2);//删除一条边

intgetFirstNeighbor(intv);//取顶点v的第一个邻接顶点

intgetNextNeighbor(intv,intw);//取v的邻接顶点w的下一邻接顶点

intgetFirstCost(intv);//取顶点v的第一个邻接顶点的cost值

intgetNextCost(intv,intw);//取v的邻接顶点w的下一邻接顶点的cost值

voidDFS(Graph&G,constT&v);//从顶点v出发对图G进行深度优先遍历的主过程

intBFS(Graph&G,constT&v);//图的广度优先搜索

voidWheCan(Graph&G);//判断是否为连通图

voidOutPut();//输出

voidHaveEdge(Graph&G);//求顶点的度

voidSerachVertex(Graph&G);//输入顶点x,查找图G:

若存在含x的顶点,则删除该结点及与之相关连的边,并作DFS遍历

voidChangeGraph(Graph&G);//将用邻接表表示的数转换为邻接矩阵表示

voidInput();//输入

};

#include

template

Graph:

:

Graph()//构造函数:

建立一个空的邻接表

{

maxVertices=100;

numVertices=0;

numEdges=0;

NodeTable=newVertex[maxVertices];//创建顶点表数组

if(NodeTable==NULL)

{

cerr<<"存储分配错!

"<

exit

(1);

}

for(inti=0;i

{

NodeTable[i].adj=NULL;

}

output=newT[maxVertices];

}

template

Graph:

:

~Graph()//析构函数:

删除一个邻接表

{

for(inti=0;i

{

Edge*p=NodeTable[i].adj;

while(p!

=NULL)

{

NodeTable[i].adj=p->link;

deletep;

p=NodeTable[i].adj;

}

}

delete[]NodeTable;//删除顶点表数组

}

template

boolGraph:

:

insertVertex(constT&vertex)//插入顶点

{

if(numVertices==maxVertices)

returnfalse;

NodeTable[numVertices].data=vertex;

numVertices++;

returntrue;

}

template

boolGraph:

:

insertEdge(intv1,intv2,Ecost)//插入边(v1,v2),权值为cost

{

if(v1>=0&&v1<=numVertices&&v2>=0&&v2<=numVertices)

{

Edge*q,*p=NodeTable[v1].adj;//v1对应的边链表头z指针

while(p!

=NULL&&p->dest!

=v2)//寻找邻接顶点v2

p=p->link;

if(p!

=NULL)//找到此边不插入

returnfalse;

p=newEdge;//否则创建新节点

q=newEdge;

p->dest=v2;

p->cost=cost;

p->link=NodeTable[v1].adj;//链入v1的边链表

NodeTable[v1].adj=p;

q->dest=v1;

q->cost=cost;

q->link=NodeTable[v2].adj;//链入v2的边链表

NodeTable[v2].adj=q;

numEdges++;

returntrue;

}

else

{

cerr<<"参数有误!

请重新输入!

"<

exit

(1);

returnfalse;

}

}

template

boolGraph:

:

removeVertex(intv)

{

if(numVertices==1||v<0||v>=numVertices)

{

cerr<<"参数有误,请重新输入!

"<

exit

(1);

returnfalse;//表空或顶点超出范围

}

Edge*p,*s,*t;

intk;

while(NodeTable[v].adj!

=NULL)

{

p=NodeTable[v].adj;

k=p->dest;

s=NodeTable[k].adj;

t=NULL;

while(s!

=NULL&&s->dest!

=v)

{

t=s;

s=s->link;

}

if(s!

=NULL)

{

if(t==NULL)

NodeTable[k].adj=s->link;

else

t->link=s->link;

deletes;

}

NodeTable[v].adj=p->link;

deletep;

numEdges--;

}

numVertices--;

NodeTable[v].data=NodeTable[numVertices].data;

p=NodeTable[v].adj=NodeTable[numVertices].adj;

while(p!

=NULL)

{

s=NodeTable[p->dest].adj;

while(s!

=NULL)

if(s->dest==numVertices)

{

s->dest=v;

break;

}

else

s=s->link;

}

returntrue;

}

template

boolGraph:

:

removeEdge(intv1,intv2)

{

if(v1!

=-1&&v2!

=-1)

{

Edge*p=NodeTable[v1].adj,*q=NULL,*s=p;

while(p!

=NULL&&p->des

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

当前位置:首页 > 经管营销 > 经济市场

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

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