数据结构与算法 图的遍历与连通性共44页文档
图的遍历和联通

成都信息工程学院计算机系课程实验报告一【上机实验目的】给定一图,在遍历的基础上确定其是否是连通。
熟悉图的存储结构,深度和广度遍历以及其连通等。
二【实验环境】PC机每人1台三【上机实验内容】给定一图,在遍历的基础上确定其是否是连通。
其中要掌握图的存储结构在此基础上才能知道怎么遍历,然后要把深度遍历和广度遍历分析透,最后才解决连通的问题。
四【上机调试程序流程图】(注:可打印)(用传统流程图的形式表示)邻接矩阵存储L G)深度优先遍历int dfs(algraph gra,int i)判断图是否连通gl,int n,int e)int bfstra_fen(algraph gra)五【上机调试中出现的错误信息、错误原因及解决办法】上机过程中遇到了很多的问题,小到变量的引用,全局量的运用,地址符,指针等等。
其实这些都还好,自己可以一步一步慢慢地解决,最困难的就是一些逻辑错误,严重的时候会出现刷屏或者死机什么什么的。
六【上机调试后的源程序及还存在的问题】(注:源程序可打印)(同时记录下你对你编写此程序的其它具体想法,)#include <iostream>#include <>using namespace std;#define int_max 10000#define inf 9999#define max 20#define OK 1dj=int_max;[i][j].info=NULL;}for(int k=0;k!=;++k){cout<<"输入一条边依附的顶点和权例如:(a b 3)不包括“()”"<<endl;cin>>v1>>v2>>w;dj=w;[j][i].adj=w;}cout<<"图G邻接矩阵创建成功!"<<endl;return ;}void ljjzprint(MGraph_L G) dj<<" ";cout<<endl;}}int visited[max];ata=[i];[i].firstarc=NULL;}for(i=0;i!=;++i){for(j=0;j!=;++j){if[i].firstarc==NULL){if[i][j].adj!=int_max&&j!={arc=(arcnode *)malloc(sizeof(arcnode));arc->adjvex=j;[i].firstarc=arc;arc->nextarc=NULL;p=arc;++j;while[i][j].adj!=int_max&&j!={tem=(arcnode *)malloc(sizeof(arcnode));tem->adjvex=j;[i].firstarc=tem;tem->nextarc=arc;arc=tem;++j;}--j;}}else{if[i][j].adj!=int_max&&j!={arc=(arcnode *)malloc(sizeof(arcnode));arc->adjvex=j;p->nextarc=arc;arc->nextarc=NULL;p=arc;}}}}=;=;cout<<"图G邻接表创建成功!"<<endl;return 1;}void adjprint(algraph gra) irstarc;while(p!=NULL){cout<<p->adjvex;p=p->nextarc;}cout<<endl;}}int firstadjvex(algraph gra,vnode v)ata;enqueue(q,i);while(!queueempty(q)){dequeue(q,e);for(we=firstadjvex(gra,[e]);we>=0;we=nextadjvex(gra,[e],we)){if(!visited[we]){visited[we]=1;cout<<[we].data;enqueue(q,we);}}}}}int dfs(algraph gra,int i)ata;for(we=firstadjvex(gra,[i]);we>=0;we=nextadjvex(gra,[i],we)){we1=we;if(visited[we]==0)dfs(gra,we);we=we1;}return 1;}int dfstra(algraph gra){int i,j;for(i=0;i!=;++i){visited[i]=0;}for(j=0;j!=;++j){if(visited[j]==0)dfs(gra,j);}return 0;}/*判断图GL是否连通*/void judgeconnect(algraph gl,int n,int e) {int i,b;int temp = 0; //temp记录图中的边数eb = 1;temp = n - 1;if(e < n-1) { //如果边数e小于定点数n-1,则图肯定不连通cout<<"这个图是不连通的!因为e < n-1。
图的遍历和连通性

• 如果使用邻接表来表示图,则BFS循环的总时间代价为 d0 + d1 + … + dn-1 = O(e),其中的 di 是顶点 i 的度。
其算法也不是递归的。
• void BFSTraverse(Graph G, Status (*Visit)(int v)){
• for (v=0; v<G.vexnum; ++v)
•
visited[v] = FALSE; //初始化访问标志
• InitQueue(Q); // 置空的辅助队列Q
• for ( v=0; v<G.vexnum; ++v )
•(2)如何避免重复访问某个顶点?
•答:创建一个一维数组visited[0..n-1](n是图中顶 点的数目),用来记录每个顶点是否已经被访问过。
•(3)广度优先搜索有回退的情况吗?
1•
•答:广度优先搜索是一种分层的搜索过程,每向前走
一步可能访问一批顶点,不像深度优先搜索那样有回
退的情况。因此广度优先搜索不是一个递归的过程,
•}
7•
DFS 算法效率分析:
(设图中有 n 个顶点,e 条边)
(1)如果用邻接矩阵来表示图,遍历图中每一 个顶点都要从头扫描该顶点所在行,因此遍历全 部顶点所需的时间为O(n2)。
(2)如果用邻接表来表示图,虽然有 2e 个表结 点,但只需扫描 e 个结点即可完成遍历,加上访 问 n个头结点的时间,因此遍历图的时间复杂度 为O(n+e)。
• 若此时图中尚有顶点未被访问,则另选图中一个未曾 被访问的顶点作起始点,重复上述过程,直至图中 所有顶点都被访问到为止。
9•
数据结构与算法 图的遍历与连通性

数据结构与算法图的遍历与连通性数据结构与算法:图的遍历与连通性在计算机科学中,数据结构和算法是解决各种问题的基石。
其中,图作为一种重要的数据结构,其遍历和连通性的研究具有至关重要的意义。
让我们先来理解一下什么是图。
简单来说,图是由顶点(也称为节点)和边组成的结构。
顶点代表了事物或者对象,而边则表示顶点之间的关系。
例如,在一个社交网络中,人可以被视为顶点,而人与人之间的好友关系就是边。
图的遍历是指按照一定的规则访问图中的所有顶点。
常见的图遍历算法有深度优先遍历和广度优先遍历。
深度优先遍历就像是一个勇敢的探险家,一头扎进未知的领域,勇往直前,直到走投无路,然后回溯。
它的基本思想是先访问一个顶点,然后沿着一条未访问过的边递归地访问下一个顶点,直到没有可访问的边,再回溯到之前的顶点,继续探索其他未访问的边。
想象一下你在一个迷宫中,选择一条路一直走到底,直到遇到死胡同或者已经没有新的路可走,然后再返回之前的岔路口,选择另一条路继续前进。
广度优先遍历则像是一个谨慎的旅行者,逐层探索。
它先访问起始顶点,然后依次访问其所有相邻的顶点,再依次访问这些相邻顶点的相邻顶点,以此类推。
这就好比你在散播消息,先告诉离你最近的人,然后他们再告诉他们附近的人,一层一层地传播出去。
那么,为什么我们要进行图的遍历呢?这是因为通过遍历图,我们可以获取图的各种信息,比如顶点之间的关系、图的结构特点等。
在实际应用中,图的遍历有着广泛的用途。
例如,在搜索引擎中,通过遍历网页之间的链接关系来抓取和索引网页;在社交网络分析中,遍历用户之间的关系来发现社区结构等。
接下来,我们谈谈图的连通性。
连通性是指图中顶点之间是否存在路径相连。
如果从图中的任意一个顶点都可以到达其他任意一个顶点,那么这个图就是连通图;否则,就是非连通图。
判断图的连通性是一个重要的问题。
一种常见的方法是从某个顶点开始进行遍历,如果能够访问到所有的顶点,那么图就是连通的;否则,图是非连通的。
数据结构-图的连通性

③数据结构的动态分析 (closedge[5].adjvex,G.vexs[5])
∞ 6 1 6 ∞ 5 1 5 ∞ 5 6 5 ∞ 3 6 ∞ ∞ 4
i
1
v2 5
3
5 v4
2
v3
5 ∞ 5 ∞ ∞ 2 2
∞ 3 6 ∞ ∞ 6 3
∞ ∞ 4 2 6 ∞ 4 5
3
6
4
2
4 v 5
6
v6
5
G.vexs:
一、最小生成树
2.实例:V={v1,v2,v3,v4,v5,v6}
①任取u0=v1, 则:U={v1}, V-U={v2,v3,v4,v5,v6}
v2 6
v1 5 1 5 v3 3 6 4 2 5 v4
v5
6
v6
一、最小生成树
2.实例:V={v1,v2,v3,v4,v5,v6}
①任取u0=v1, 则:U={v1}, V-U={v2,v3,v4,v5,v6} ②取边(v1,v3),则:U={v1,v3} V-U={v2,v4,v5,v6}
一、最小生成树
3.算法的实现:
③数据结构的动态分析 G.arcs如下:
0 0 1 2 3 4 5 1 2 3 4 5 6
0
v1 5 1
1
v2 5
3
5 v4
2
v3
∞ 6 1 6 ∞ 5 1 5 ∞ 5 6 5 ∞ 3 6 ∞ ∞ 4
i
5 ∞ 5 ∞ ∞ 2 2
∞ 3 6 ∞ ∞ 6 3
∞ ∞ 4 2 6 ∞ 4 5
v2 6
v1 5 1 5 v3 3 6 4 2 5 v4
v5
6
v6
④取边(v6,v4),则:U={v1,v3, v6,v4} V-U={v2,v5} ⑤取边(v3,v2),则:U={v1,v3, v6,v4,v2} ⑥取边(v2,v5),则:U={v1,v3, v6,v4,v2,v5}
数据结构课程设计--图的遍历

1.引言数据结构是计算机科学与技术专业的一门核心专业基础课程,是一门理论性强、思维抽象、难度较大的课程。
在软件工程专业的课程体系中起着承上启下的作用,学好数据结构对于提高理论认知水平和实践能力有着极为重要的作用。
通过本门课程的学习,我们应该能透彻地理解各种数据对象的特点,学会数据的组织方法和实现方法,并进一步培养良好的程序设计能力和解决实际问题的能力。
我认为学习数据结构的最终目的是为了获得求解问题的能力。
对于现实世界中的问题,我们应该能从中抽象出一个适当的数学模型,该数学模型在计算机内部用相应的数据结构来表示,然后设计一个解此数学模型的算法,再进行编程调试,最后获得问题的解答。
图是一种非常重要的数据结构,在《数据结构》中也占着相当大的比重。
这个学期的数据结构课程中,我们学习了很多图的存储结构,有邻接矩阵、邻接表、十字链表等。
其中邻接矩阵和邻接表为图的主要存储结构。
图的邻接矩阵存储结构的主要特点是把图的边信息存储在一个矩阵中,是一种静态存储方法。
图的邻接表存储结构是一种顺序存储与链式存储相结合的存储方法。
从空间性能上说,图越稀疏邻接表的空间效率相应的越高。
从时间性能上来说,邻接表在图的算法中时间代价较邻接矩阵要低。
本课程设计主要是实现使用邻接表存储结构存储一个图,并在所存储的图中实现深度优先和广度优先遍历以及其链表结构的输出。
2.需求分析2.1 原理当图比较稀疏时,邻接表存储是最佳的选择。
并且在存储图的时候邻接表要比邻接矩阵节省时间。
在图存储在系统中后,我们有时还需要对图进行一些操作,如需要添加一个顶点,修改一个顶点,或者删除一个顶点,而这些操作都需要一图的深度优先及广度优先遍历为基础。
本系统将构建一个图,图的结点存储的是int型数据。
运行本系统可对该图进行链式结构输出、深度优先及广度优先遍历。
控制方法如下:表2-1 控制键的功能2.2 要求(1)建立基于邻接表的图;(2)对图进行遍历;(3)输出遍历结果;2.3 运行环境(1)WINDOWS 7系统(2)C++ 编译环境2.4 开发工具C++语言3.数据结构分析本课程设计是针对于图的,程序中采用邻接表进行数据存储。
数据结构第15讲_图的遍历与连通性和最小生成树_C

(3)从那些其中一个端点已在 U 中,另一端点仍 在 U 外的所有边中,找一条最短(即权值最 小)的边,设该边为(Vi,Vj),其中 Vi∈U, Vj∈V-U,并把该边和顶点 Vj分别并入 T 的 边集 TE 和顶点集 U;
基本思想
为使生成树上总的权值最小,应使每条边上 的权值尽可能小,自然应从权值最小的边选起, 直至选出n-1条权值最小的边为止,同时这n-1条 边必须不构成回路。因此,并非每一条当前权值 最小的边都可选。
4.克鲁斯卡尔(Kruskal)算法
具体做法
先构造一个只含 n个顶点的森林,然后依权 值从小到大从连通网中选择边加入到森林中去, 并使森林中不产生回路,直至森林变成一棵树为 止。
6
23 12
5
7
4
5
8
3
7
25 15
10
6
4
20
图b
2.广度优先搜索(BFS)
基本思想: 从图中某个顶点V0出发,并在访问此顶点后依
次访问V0的所有未被访问过的邻接点,之后按这些 顶点被访问的先后次序依次访问它们的邻接点,直 至图中所有和V0有路径相通的顶点都被访问到;
若此时图中尚有顶点未被访问,则另选图中一 个未曾被访问的顶点作起始点;
重复上述过程,直至图中所有顶点都被访问到 为止。
(4)如此进行下去,每次往生成树里并入一个顶点 和一条边,直到 n-1 次后,把所有 n 个顶点 都并入生成树 T 的顶点集 U 中,此时 U=V, TE中包含有(n-1)条边;这样,T 就是最后 得到的最小生成树。
例:求下图最小生成树。假设开始顶点就选为顶点1, 故有U={1},V-U={2,3,4,5,6}
数据结构的连通性问题

7.2 图的存储结构
7.3 图的遍历
7.4 图的连通性问题 7.5 有向无环图及其应用 7.6 最短路径
£7.4 图的连通性问题
£7.4.1 无向图的连通分量和生成树
(1)连通图 在对无向图进行遍历时,对于连通图,仅需从图中任一顶点出发, 进行深度优先搜索或广度优先搜索,便可访问到图中所有结点。 深度优先生成树:在连通图中,由深度优先搜索得到的生成树。 广度优先生成树:在连通图中,由广度优先搜索得到的生成树。 (2)非连通图 在对无向图进行遍历时,对于非连通图,需从多个顶点出发进行 搜索,而每一次从一个新的起始点出发进行搜索过程中得到的顶点访 问序列恰为其各个连通分量中的顶点集。 生成森林:在非连通图中,每个连通分量中的顶点集和遍历时走 过的边一起构成若干棵生成树,这些连通分量的生成树组成非连通图 的生成森林。 深度优先生成森林:在非连通图中,由深度优先搜索得到的生成 森林。 广度优先生成森林:在非连通图中,由广度优先搜索得到的生成 森林。
0
1
2
3
4
5
6
Adjvex Lowcost
d a e c 19 12 7 5
d
e
a
3
8
14
a e 21 18 16 d
void MiniSpanTree_P(MGraph G, VertexType u) { //用普里姆算法从顶点u出发构造网G的最小生成树
k = LocateVex ( G, u ); for ( j=0; j<G.vexnum; ++j ) // 辅助数组初始化 if (j!=k) closedge[j] = { u, G.arcs[k][j].adj }; closedge[k].lowcost = 0; // 初始,U={u} for (i=0; i<G.vexnum; ++i) { 继续向生成树上添加顶点; }
图的遍历(深度优先遍历和广度优先遍历)

遍历规则 从图中某结点v0出发,深度优先遍历(DFS: Depth First Search)图的规则为: 访问v0; 对v0的各个出点v01,v02,…,v0m,每次从它们中按一定方式(也可任选)选取一个未被访问过的结点,从该结点出发按深度优先遍历方式遍历。 然,因为我们没有规定对出点的遍历次序,所以,图的深度优先遍历结果一般不唯一。
20.2 深度优先遍历
例如,对图 20‑1给出的有向图与无向图,一些遍历结果(结点访问次序)为: 左图:从1出发:1,2,4,5;或1,5,2,4 从2出发:2,1,5,4;或2,4,1,5 右图:从a出发:a,b,c,d;或a,b,d,c; … …
A 如果不想让visited或top做为函数参数,也可以在函数中将其定义为static型量。但是,这样的程序是不可再入的,即函数再次被调用时,static型的量也不重新初始化,造成错误!
上面函数中的参数visited和top实质上是中间变量,只是为了避免在递归调用时重新初始化而放在参数表中,造成使用的不方便,为此,做个包装程序: long DFS1(int g[][CNST_NumNodes], long n, long v0, long *resu ) { char *visited; long top=0; visited = new char[n]; for (long i=0; i<n; i++) visited[i]=0; long num=DFS1( g, n, v0, visited, resu, top ); delete visited; return num; }
深度优先遍历非递归算法的一般性描述。
long DFS_NR(图g,结点v0)
单击此处可添加副标题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
template<class T, class E>
void DFS (Graph<T, E>& G, int v, bool visited[ ]) {
cout << G.getValue(v) << ' '; //访问顶点v
visited[v] = true;
//作访问标记
int w = G.getFirstNeighbor (v); //第一个邻接顶点
广度优先搜索是一种分层的搜索过程, 每向前 走一步可能访问一批顶点, 不像深度优先搜索 那样有往回退的情况。因此, 广度优先搜索不 是一个递归的过程。
为了实现逐层访问, 算法中使用了一个队列, 以 记忆正在访问的这一层和上一层的顶点, 以便 于向下一层访问。
为避免重复访问, 需要一个辅助数组 visited [ ], 给被访问过的顶点加标记。
深度优先搜索DFS (Depth First Search)
深度优先搜索的示例
123
123
A
B
E
A
B
E
7D C5 G4
7D C 5 G 4
6F H
I
8 前进 9
深度优先搜索过程
6F H
I
回退
89
深度优先生成树
DFS 在访问图中某一起始顶点 v 后, 由 v 出发,
访问它的任一邻接顶点 w1; 再从 w1 出发, 访问 与 w1邻接但还没有访问过的顶点 w2; 然后再从 w2 出发, 进行类似的访问, … 如此进行下去, 直 至到达所有的邻接顶点都被访问过的顶点 u 为
while (w >= 0) {
//若邻接顶点w存在
if ( !visited[w] ) DFS(G, w, visited);
//若w未访问过, 递归访问顶点w
w = G.getNextNeighbor (v, w); //下一个邻接顶点
}
}
广度优先搜索BFS (Breadth First Search)
for (i = 0; i < n; i++) visited[i] = false;
int loc = G.getVertexPos (v); // 取顶点号
cout << G.getValue (loc) << ' '; // 访问顶点v
visited[loc] = true;
// 做已访问标记
int i, loc, n = G.NumberOfVertices( ); // 顶点个数 bool *visited = new bool[n]; // 创建辅助数组 for (i = 0; i < n; i++) visited [i] = false;
// 辅助数组 visited 初始化 loc = G.getVertexPos(v); DFS (G, loc, visited);// 从顶点0开始深度优先搜索 delete [ ] visited; // 释放visited }
// 若邻接顶点w存在
if (!visited[w]) {
// 若未访问过
cout << G.getValue (w) << ' '; // 访问
visited[w] = true;
Q.EnQueue (w); // 顶点 w 进队列
}
w = G.getNextNeighbor (loc, w);
Queue<int> Q; Q.EnQueue (loc);
// 顶点进队列, 实现分层访问
while (!Q.IsEmpty( ) ) { // 循环, 访问所有结点
Q.DeQueue (loc);
w = G.getFirstNeighbor (loc); // 第一个邻接顶点
while (w >= 0) {
// 找顶点 loc 的下一个邻接顶点
}
}
// 外层循环,判队列空否
delete [ ] visited;
}
连通分量 (Connected component)
当无向图为非连通图时,从图中某一顶点出 发,利用深度优先搜索算法或广度优先搜索 算法不可能遍历到图中的所有顶点,只能访 问到该顶点所在最大连通子图(连通分量) 的所有顶点。
若从无向图每一连通分量中的一个顶点出发 进行遍历, 可求得无向图的所有连通分量。
例如,对于非连通的无向图,所有连通分量 的生成树组成了非连通图的生成森林。
A
H
K
BБайду номын сангаасDE
I
L MN
F
G
J
O
非连通无向图
A
H
K
BCDE
I
L MN
辅助数组visited[ ]的初始状态为 0, 在图的遍 历过程中, 一旦某一个顶点 i 被访问, 就立即 让visited[i]为 1, 防止它被多次访问。
图的遍历的分类: 深度优先搜索
DFS (Depth First Search) 广度优先搜索
BFS (Breadth First Search)
止。接着, 退回一步, 退到前一次刚访问过的
顶点, 看是否还有其它没有被访问的邻接顶点。
如果有, 则访问此顶点, 之后再从此顶点出发,
进行与前述类似的访问; 如果没有, 就再退回一
步进行搜索。重复上述过程, 直到连通图中所
有顶点都被访问过为止。
图的深度优先搜索算法
template<class T, class E> void DFS (Graph<T, E>& G, const T& v) { // 从顶点 v 出发对图 G 进行深度优先遍历的主过程
图的广度优先搜索算法
template <class T, class E> void BFS (Graph<T, E>& G, const T& v) {
int i, w, n = G.NumberOfVertices( ); // 图中顶点个数
bool *visited = new bool[n];
广度优先搜索的示例
125
A
B
E
1 25
A
B
E
4D C3 G7
4D C 3 G7
6F H
I
89
广度优先搜索过程
6F
H
I
89
广度优先生成树
BFS在访问了起始顶点 v 之后, 由 v 出发, 依次 访问 v 的各个未被访问过的邻接顶点 w1, w2, …, wt , 然后再顺序访问 w1, w2, …, wt 的所 有还未被访问过的邻接顶点。再从这些访问 过的顶点出发,再访问它们的所有还未被访 问过的邻接顶点,… 如此做下去,直到图中 所有顶点都被访问到为止。