图形结构10.docx
《图形结构10.docx》由会员分享,可在线阅读,更多相关《图形结构10.docx(47页珍藏版)》请在冰豆网上搜索。
图形结构10
第十章图形结构
10.1图的基本概念
10.2图的存储结构
10.3图的遍历
10.4生成树问题
10.5最短路径问题
图是一种比线性表、二叉树更复杂的数据结构,任意两个数据元素之间都可以有关系。
图的应用非常能够广泛,已渗透到诸如语言学、逻辑学、物理、化学、电讯工程、计算机学科等其他分支中。
10.1图的基本概念
1.图的定义
在图G中包含了两个集合,一个是由顶点(Vertices或nodes)所构成的有限的非空集合,另一个是由边(Edges或Arcs)所构成的有限非空集合,我们用G(V,E)来表示。
2.无向图
一个图G中,如果用一条无序偶代表一条边,则称边是无向的,用圆括号将一对结点括起来表示无向边,此时图G称为无向图。
集合的概念中,我们可以将上图表示为:
V(G)=(1,2,3,4)
E(G)={(1,2),(1,3),(2,3),(2,4),(3,4)}
3.有向图
一个图G中如果用结点的有序偶代表一条边,则称边是有向的,用尖括号将一对结点括起来表示有向边,此时称图G为有向图。
从集合的概念中,我们可以将上图表示为:
V(G)=(1,2,3,4)
E(G)={<1,2>,<1,3>,<1,4>,<2,4>,<3,4>}
4.完全图
一个有n个结点的无向图,其边的最大数目为n*(n-1)/2,若一个图就具有最大值的边数,则该图为完全图。
一个有n个结点的有向图,其边的最大数目为n*(n-1),若一个有向图就具有最大值的边数,则该图为有向完全图。
5.子图
所谓的子图(Sub-Graph)是指由图G中取出的部分集合,如下图为图G
则以下各图皆为其子图形
6.路径
所谓路径(Path)是指在图中从顶点A到达顶点B,经过的所有边。
例如下图从顶点1到顶点5的路径为,,,而路径的长度为经过的边数,在这个例子中,路径的长度为3。
7.简单路径
所谓简单路径(SimplePath)是指在图中除了起点和终点可以重复(不重复亦可)外,其余的顶点皆不相同的路径。
如上图的,,为简单路径,而,,,,,不是简单路径,因为在这条路径中顶点1和顶点2重复经过。
8.回路
所谓回路(Cycle)是指在图中,起点和终点相同的简单路径。
如下图中,,,就是一条回路,而,,,也是一条回路。
9.强连通图
如果在有向图中,任意两个顶点间皆存在一条路径可到对方,则称为强连通图(StronglyConnectedGraph)。
10.2图形的表示法
1.数组表示法
数组表示法(AdjacentMatrix)是以一个n*n的数组来表示一个具有n个顶点的图。
我们以数组的下标值来表示顶点,以数组的内容值来表示顶点间的边是否存在(以1表示存在边,以0表示不存在边)。
如下图的无向图形:
其邻接数组为:
01234
在无向图中,邻接数组是一个对称矩阵。
但在有向图中,邻接数组内容不一定对称。
下面用一个程序实例来说明图的数组表示法
1.程序目的
设计一个将图转成邻接数组的程序
2.程序构思
用户输入各个边,再将边转成邻接数组。
3.程序源代码
01//==============ProgramDescription=============
02//程序名称:
mgraph.java
03//程序目的:
设计一个将图形转成邻接数组的程序.
04//WrittenByKuo-YuHuang.(WANTStudio.)
05//======================================
06importConsoleReader.*;//引入已定义的数据输入类
07
08publicclassmgraph
09{
10publicstaticintMax=6;//定义最大可输入数
11//图形邻接数组
12publicstaticintGraph[][]=newint[Max][Max];
13
14publicstaticvoidmain(Stringargs[])
15{
16intSource;//起始顶点
17intDestination;//终止顶点
18inti,j;//循环计数变量
19ConsoleReaderconsole=newConsoleReader(System.in);
20
21for(i=0;i22for(j=0;j23Graph[i][j]=0;
24while(true)
25{
26System.out.print(“PleaseinputtheEdge’ssource(-1forExit):
”);
27Source=console.readInt();
28if(Source==-1)
29break;
30
31System.out.print(“PleaseinputtheEdge’sDestination:
”);
32Destination=console.readInt();
33
34//错误:
自身循环
35if(Source==Destination)
36System.out.println(“@Error@:
SelfLoop!
!
”);
37//错误:
超出范围
38elseif(Source>=Max||Destination>=Max)
39System.out.println(“@Error@:
Outofrange!
!
”);
40else//调用建立邻接数组
41CreateMGraph(SourceDestination);
42}
43System.out.println(“##Graph##”);
44PrintMGraph();//调用输出邻接数组数据
45}
46
47//----------------------------------------------------
48//输出邻接数组数据
49//----------------------------------------------------
50publicstaticvoidPrintMGraph()
51{
52inti,j;//循环计数变量
53
54System.out.print(“Vertice”);
55for(i=0;i56System.out.print(““+i+”“);
57System.out.println(““);
58
59for(i=0;i60{
61System.out.print(““+i+”“);
62for(j=0;j63System.out.print(““+Graph[i][j]+”“);
64System.out.println(““);
65}
66}
67
68//----------------------------------------------------
69//以邻接数组建立图
70//----------------------------------------------------
71publicstaticvoidCreateMGraph(intVerticel,intVertice2)
72{
73Graph[Vertice1][Vertice2]=1;//将数组内容设为1
74}
75}
2.邻接表表示法
邻接表法(AdjacencyList)是以链表来记录各顶点的邻接顶点。
其结点结构如下:
如下图的有向图:
其邻接表为:
3.多重邻接表表示法
在无向图的邻接表表示法中,每一个边都会出现两次。
在多重邻接表中结点可以在多个列表中使用。
多重邻接表的结点结构如下:
每一个结点记录着一个边的数据。
如下的无向图形:
有5条边E1=(1,2),E2=(1,3),E3=(1,4),E4=(2,4),E5=(3,4)。
其多重邻接表为:
10.3图的遍历
遍历是图的基本操作。
对于一个图,从其中的一个顶点出发,以某种次序顺序的访问图中的每个顶点,并且每个顶点只能被访问一次,这一过程称为图的遍历。
10.3.1深度优先遍历
深度优先遍历类似树的先根遍历。
1.算法描述
在图中,如果以顶点V作为起始点开始搜索,我们从顶点V的邻接表中选择一个未搜索过的顶点W,由顶点W继续进行深度优先法的搜索,每搜索一个顶点,便把该顶点压入堆栈。
直到搜索到已经没有任何邻接的未遍历的顶点U,此时取栈顶顶点,回到上一层顶点继续搜索未遍历的顶点,直到所有的顶点皆搜索过为止。
2.实例
对于下图的无向图形:
操作过程:
(1)如果从顶点1开始深度优先搜索,顶点1存入堆栈。
(2)顶点1的邻接顶点为顶点2和顶点3,选择顶点2(也可以选择顶点3)往下继续深度优先搜索,将顶点2存入堆栈。
(3)顶点2的邻接顶点为顶点4和顶点5,选择顶点4往下继续深度优先搜索,将顶点4存入堆栈。
(4)顶点4的邻接顶点为顶点8,将顶点8存入堆栈。
(5)发现顶点8的邻接顶点为顶点4、顶点5、顶点6和顶点7,顶点4已经搜索过,选择顶点5继续深度优先搜索,将顶点5存入堆栈。
5
(6)发现顶点5的邻接顶点为顶点2,顶点2已经搜索过,退回到顶点8,将顶点5从堆栈取出。
(7)发现顶点8的邻接顶点为顶点4、顶点5、顶点6和顶点7,顶点4和顶点5已经搜索过,选择顶点6继续深度优先搜索,将顶点6存入堆栈。
(8)发现顶点6的邻接顶点为顶点3,选择顶点3继续深度优先搜索,将顶点3存入堆栈。
3
(9)发现顶点3的邻接顶点为顶点7,选择顶点7继续深度优先搜索,将顶点7存入堆栈,
7
(10)发现顶点7的邻接顶点皆搜索完,取出堆栈中顶点,堆栈中所有顶点的邻接皆已搜索(此时堆栈为空),结束。
所以搜索的顺序为:
顶点1、顶点2、顶点4、顶点8、顶点5、顶点6、顶点3、顶点7
因为深度优先搜索时,同一深度的邻接顶点,可选择其中一个继续进行邻接顶点的深度搜索,所以深度优先搜索的顺序不是惟一的。
设计深度优先搜索程序时,我们可采用堆栈来存储未搜索的邻接顶点,或者采用递归来调用深度优先搜索函数,搜索未曾搜索过的顶点。
3.程序实现
(1)程序目的
设计一个深度优先搜索法来搜索上述图形的程序
(2)程序构思
递归调用深度优先搜索法
(3)程序源代码
//==========ProgramDescription============
//程序名称:
dfs.java
//程序目的:
设计一个深度优先搜索法来搜索图形的程序.
//WrittenByKuo-YuHuang.(WANTStudio.)
//=================================
importConsoleReader.*;//引入已定义的数据输入类
publicclassdfs
{
publicstaticintVertexNum=9;
publicstaticint[]Visited=newint[VerexNum];//搜索记录
publicstaticint[][]Node=
{{1,2},{2,1},{1,3},{3,1},{2,4},
{4,2},{2,5},{5,2},{3,6},{6,3},
{3,7},{7,3},{4,8},{8,4},{5,8},
{8,5},{6,8},{8,6},{7,8},{8,7}};
//图形邻接数组
publicstaticintGraph[][]=newint[VertexNum][VertexNum];
publicstaticvoidmain(Stringargs[])
{
intSource;//起始顶点
intDestination;//终止顶点
inti,j;//循环计数变量
ConsoleReaderconsole=newConsoleReader(System.in);
for(i=0;ifor(j=0;jGraph[i][j]=0;
for(i=0;i<20;i++)
{
//调用建立邻接数组
CreateMGraph(Node[i][0],Node[i][j]);
}
System.out.println(“##Graph##”);
PrintMGraph();//调用输出邻接数组数据
System.out.println(“Deph-First-Search:
”);
System.out.print(“[BEGIN]==>”);
DFS
(1);
System.out.print(“[END]”);
}
//-------------------------------------------------
//深度优先搜索法
//-------------------------------------------------
publicstaticvoidDFS(intVertex)
{
intPointer;//结点声明
inti;
Visited[Vertex]=1;//已搜索
System.out.print(“[“+Vertex+”]==>”);
for(i=1;i{
if(Graph[Vertex][i]==1&&Visited[i]==0)
DFS(i);//递归调用
}
}
//-------------------------------------------------
//输出邻接数组数据
//-------------------------------------------------
publicstaticvoidPrintMGraph()
{
inti,j;//循环计数变量
System.out.print(“Vertice”);
for(i=0;iSystem.out.print(““+i+”“);
System.out.println(“”);
for(i=0;i{
System.out.print(““+i+”“);
for(j=0;jSystem.out.print(““+Graph[i][j]+”“);
System.out.println(““);
}
}
//-------------------------------------------------
//以邻接数组建立图形
//-------------------------------------------------
publicstaticvoidCreateMGraph(intVerticel,intVertice2)
{
Graph[Vertice1][Vertice2]=1;//将数组内容设为1
}
}
10.3.2广度优先遍历
广度优先遍历类似于树的按层遍历。
1.算法描述
在图中,如果以顶点V作为起始点开始搜索,我们从顶点V的邻接表中选择一个未搜索过的顶点W,将顶点V的所有邻接顶点搜索过后,再继续对顶点W的所有邻接顶点进行广度优先法的搜索,然后再继续搜索顶点V的下一个邻接顶点的所有邻接顶点,重复进行广度优先搜索,直到所有的邻接顶点皆搜索过为止。
通常是使用队列来存储邻接顶点,每搜索一个邻接顶点便把其所有的邻接顶点存入队列中,直到队列空为止。
2.实例
对于下图的无向图形
广度优先搜索的操作过程如下:
(1)如果从顶点4开始广度优先搜索,将顶点4存入队列中。
4
(2)搜索顶点4,将顶点4的邻接顶点存入队列中,将顶点4从队列中取出。
2
(3)搜索顶点2,将顶点2的邻接顶点存入队列中,邻接顶点4已搜索过,不必存入队列中。
将顶点2从队列中取出。
8
(4)搜索顶点8,将顶点8的邻接顶点存入队列中,邻接顶点4已搜索过和邻接顶点5已再队列中,所以不必存入队列,将顶点8从队列中取出。
1
(5)搜索顶点1,将顶点1的邻接顶点存入队列中,邻接顶点2已搜索过,不必存入队列中,将顶点1从队列中取出。
5
(6)搜索顶点5,将顶点5的邻接顶点存入队列中,邻接顶点2和邻接顶点8已搜索过,不必存入队列,将顶点5从队列中取出。
6
(7)搜索顶点6,将顶点6的邻接顶点存入队列中,邻接顶点8已搜索过和邻接顶点3已在队列中,所以不必存入队列,将顶点6从队列中取出。
7
(8)搜索顶点7,将顶点7的邻接顶点存入队列中,邻接顶点8已搜索过和邻接顶点3已在队列中,不必存入队列中,将顶点7从队列中取出。
3
(9)搜索顶点3,顶点3的邻接顶点皆已搜索过,不必存入队列。
将顶点3从队列中取出,此时队列为空,结束搜索。
所以广度优先搜索的顺序为:
顶点4,顶点2,顶点8,顶点1,顶点5,顶点6,顶点7,顶点3
因为广度优先搜索时,一个顶点可以有多个邻接点,选择其中一个继续进行邻接顶点的广度搜索,所以广度优先搜索的顺序也不是惟一的。
3.程序实现
程序源代码
01//==========ProgramDescription============
02//程序名称:
bfs.java
03//程序目的:
设计一个广度优先搜索法来搜索图形的程序.
04//WrittenByKuo-YuHuang.(WANTStudio.)
05//=================================
06importConsoleReader.*;//引入已定义的数据输入类
07
08publicclassbfs
09{
10publicstaticintVertexNum=9;
11publicstaticint[]Visited=newint[VerexNum];//搜索记录
12publicstaticint[][]Node=
13{{1,2},{2,1},{1,3},{3,1},{2,4},
14{4,2},{2,5},{5,2},{3,6},{6,3},
15{3,7},{7,3},{4,8},{8,4},{5,8},
16{8,5},{6,8},{8,6},{7,8},{8,7}};
17publicstaticintGraph[][]=newint[VertexNum][VertexNum];
18
19publicstaticvoidmain(Stringargs[])
20{
21intSource;//起始顶点
22intDestination;//终止顶点
23int,j;//循环计数变量
24ConsoleReaderconsole=newConsoleReader(System.in);
25
26for(i=0;i27for(j=0;j28Graph[i][j]=0;
29
30for(i=0;i<20;i++)
31{
32//调用建立邻接数组
33CreateMGraph(Node[i][0],Node[i][1]);
34}
35
36System.out.println(“##Graph##”);
37PrintMGraph();//调用输出邻接数组数据
38
39System.out.println(“Bradth-First-Search:
”);
40System.out.print(“[BEGIN]==>”);
41DFS(4);
42System.out.print(“[END]”);
43}
44
45//--------------------