数据结构图的建立与输出课程设计Word文档下载推荐.docx
《数据结构图的建立与输出课程设计Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《数据结构图的建立与输出课程设计Word文档下载推荐.docx(17页珍藏版)》请在冰豆网上搜索。
常用的就有我们熟悉的邻接表、邻接多重表和十字链表。
所以,我们打算采用邻接表的方法设计图的存储结构,包括图的建立与存储。
二设计方案及工作原理
1.图有两种主要的存储结构,它们是邻接矩阵表示法和邻接表表示法。
设图A=(V,E)是一个有n个顶点的图,图的邻接矩阵是一个二维数组A。
edge[n][n], 用来存放顶点的信息和边或弧的信息。
(1)无向图的邻接矩阵是对称的;
有向图的邻接矩阵可能是不对称的。
(2)在有向图中,统计第i行1的个数可得顶点i的出度,统计第j行1的个数可得顶点j的入度。
在无向图中,统计第i行(列)1的个数可得顶点i的度。
图的邻接表(AdjacencyList)存储表示法
邻接表是图的一种链式存储结构,它对图中每个顶点建立一个单链表,第i个单链表中的结 点表示依附于顶点vi的边(对有向图是以顶点vi为尾的弧),每个结点由三个域组成:
邻接点域(adjvex)指示与顶点vi邻接的点在图中的位置,链域(nextarc)指示下一条边或弧的结点,数据 域(info)存储和边或弧相关的信息(如权值)。
每个链表上附设一个表头结点,包含数据域(data)和链域(firstarc)指向链表中的第一个结点,这些表头结点通常以顺序结构的形式存储,
以便随机访问任一顶点的链表。
在无向图的邻接表中,顶点vi的度等于第i个链表中的结点数;
在有向图的邻接表中,顶点vi的出度等于第i个链表中的结点数,求入度必须遍历整个邻接表,为便于求vi的入度需建立有 向图的逆邻接表(是以顶点vi为头的弧所建立的邻接表)。
2.图的邻接表存储表示:
#defineMAX_VERTEX_NUM20
typedefstructArcNode{
intadjvex;
//该弧所指向的顶点的位置
structArcNode*nextarc;
//指向下一条弧的指针
InfoType*info;
//该弧相关信息的指针
}ArcNode;
typedefstructVNode{
VertexTypedata;
//顶点信息
ArcNode*firstarc;
//指向第一条依附该顶点的弧
}VNode,AdjList[MAX_VERTEX_NUM];
typedefstruct{
AdjListvertices;
intvexnum,arcnum;
//图的当前顶点数和弧数
intkind;
//图的种类标志
}ALGraph;
3.有向图的十字链表存储表示法
十字链表(OrthogonalList)是有向图的另一种链式存储结构,可以看成是将有向图的邻接表和逆邻接表结合起来得到的一种链表。
typedefstructArcBox{
inttailvex,headvex;
//该弧的尾和头顶点的位置
structArcBox*hlink,*tlink;
//分别指向下一个弧头相同和弧尾相同的弧的指针域
InfoType*info;
}ArcBox;
typedefstructVexNode{
ArcBox*firstin,*firstout;
//分别指向该顶点第一条入弧和出弧
}VexNode;
typedefstruct{
VexNodexlist[MAX_VERTEX_NUM];
//表头向量
intvexnum,arcnum;
//有向图的当前顶点数和弧数
}OLGraph;
4.无向图的邻接多重表存储表示
typedefemnu{unvisited,visited}VisitIf;
typedefstructEbox{
VisitIfmark;
//访问标记
intivex,jvex;
//该边依附的两个顶点的位置
structEBox*ilink,*jlink;
//分别指向依附这两个顶点的下一条边
InfoType*info;
//该边信息指针
}EBox;
typedefstructVexBox{
VertexTypedata;
EBox*firstedge;
//指向第一条依附该顶点的边
}VexBox;
VexBoxadjmulist[MAX_VERTEX_NUM];
intvexnum,edgenum;
//无向图的当前顶点数和边数
}AMLGraph;
5.邻接矩阵表示法
设G=(V,E)是一个图,其中V={V1,V2,V3…,Vn}。
G的邻接矩阵是一个他有下述性质的n阶方阵:
1,若(Vi,Vj)∈E或<
Vi,Vj>
∈E;
A[i,j]={
1,反之
图5—2中有向图G1和无向图G2的邻接矩阵分别为M1和M2:
M1=┌0101┐
│1010│
│1001│
└0000┘
M2=┌0111┐
│1101│
└1010┘
注意无向图的邻接是一个对称矩阵,例如M2。
用邻接矩阵表示法来表示一个具有n个顶点的图时,除了用邻接矩阵中的n*n个元素存储顶点间相邻关系外,往往还需要另设一个向量存储n个顶点的信息。
因此其类型定义如下:
constvnum=…;
{图的顶点数}
typeadj=0..1;
adjmatrix=arry[1。
。
vnum,1.。
vnum]ofadj;
{邻接矩阵}
graph=record
vexs:
array[1.。
vnum]ofvextype;
{顶点向量}
arcs:
adjmatrix;
{邻接矩阵}
end;
若图中每个顶点只含一个编号i(1≤i≤vnum),则只需一个二维数组表示图的邻接矩阵.此时存储结构可简单说明如下:
typeadjmatrix=array[1。
.vnum,1.。
利用邻接矩阵很容易判定任意两个顶点之间是否有边(或弧)相联,并容易求得各个顶点的度。
对于无向图,顶点Vi的度是邻接矩阵中第i行元素之和,即
n n
D(Vi)=∑A[i,j] (或∑A[i,j])
j=1 i=1
对于有向图,顶点Vi的出度OD(Vi)为邻接矩阵第i行元素之和,顶点Vi的入度ID(Vi)为第i列元素之和。
即
n n
OD(Vi)=∑A[i,j],OD(Vi)=∑A[j,i])
j=1 j=1
用邻接矩阵也可以表示带权图,只要令
Wij,若<
Vi,Vj〉或(Vi,Vj)
A[i,j]={
∞,否则。
其中Wij为<
Vi,Vj〉或(Vi,Vj)上的权值。
相应地,网的邻接矩阵表示的类型定义应作如下的修改:
adj:
weightype;
{weightype为权类型}
图5-6列出一个网和它的邻接矩阵。
┌∞31∞∞┐
│∞∞51∞│
│∞∞∞∞∞│
│∞∞6∞∞│
└∞322∞┘
(a)网(b)邻接矩阵
图5-6网及其邻接矩阵
对无向图或无向网络,由于其邻接矩阵是对称的,故可采用压缩存贮的方法,仅存贮下三角或上三角中的元素(但不含对角线上的元素)即可。
显然,邻接矩阵表示法的空间复杂度O(n2)。
无向网邻接矩阵的建立方法是:
首先将矩阵A的每个元素都初始化成∞。
然后,读入边及权值(i,j,wij),将A的相应元素置成Wij。
无向网邻接矩阵的建立算法如下:
procedurebuild—graph(varga:
graph);
{建立无向网的邻接矩阵}
begin
fori:
=1tondoread(ga。
vexs[i]);
{读入n个顶点的信息}
fori:
=1tondo
forj:
=1toedo
ga.arcs[i,j]:
=maxint;
{将邻接矩阵的每个元素初始化成maxint,计算机内∞用最大事数maxint表示}
fork:
=1toedo{e为边的数目}
[read(i,j,w){读入边〈i,j〉和权}ga.arcs[i,j]:
=w;
ga.arcs[j,i]:
=w]end;
该算法的执行时间是O(n+n2+e),其中消耗在邻接矩阵初始化操作上的时间是O(n2),而e<
n2,所以上述算法的时间复杂度是O(n2)。
图的邻接矩阵存储表示:
#defineINFINITYINT_MAX//最大值∞
#defineMAX_VERTEX_NUM20//最大顶点个数
typedefenum{DG,DN,AG,AN}GraphKind;
//{有向图,有向网,无向图,无向网}
typedefstructArcCell{
VRTypeadj;
//VRType是顶点关系类型.对无权图,用1或0表示相邻否;
//对带权图,则为权值类型。
}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
VertexTypevexs[MAX_VERTEX_NUM];
//顶点向量
AdjMatrixarcs;
//邻接矩阵
//图的当前顶点数和弧(边)数
GraphKindkind;
}MGraph;
6、邻接表表示法
邻接表是图的一种链式存储结构为,类似于树的孩子链表表法.在邻接表中,对图中每个顶点建立一个单链表,n个顶点,就要建n个链表。
对于无向图,第i个单链表中的结点表示依赖于顶点vi的边。
对于有向图是以顶点vi为尾的弧,这个单链表称为顶点vi的单链表(即Vi的邻接表).单链表中每一个结点称为表结点,应包括两个域:
邻接点域,用以存放与vi相邻接的顶点序号;
链域用以指向民vi邻接的下一个结点。
另外,每一个单链表设一个表头结点。
每一个表头结点有两个域,一个用来存放顶点vi的信息;
另一个域用来指向vi的邻接表中的第一个结点(见图5-7)。
为了便于管理和随机访问任一顶点的单链表,将所有单链表的头结点组织成一个一维娄组.
若一个无向图有n个顶点,e条边,则它的邻接表需n个头结点和2e个表结点。
显然,在边稀疏(e〈<
n(n—1)/2)的情况下,用邻接表表示比用邻接矩阵节省存储空间.若一个有向图有n个顶点,e条边,则它的邻接表需n个头结点和e个表结点。
下面讨论在邻接表上如何求顶点的度.无向图中顶点vi的度恰为第i个单链表中的结点数。
对有向图,第i个单链表中的结点个数只是顶点vi的出度。
为了求入度,必须遍历整个邻接表。
在所有单链表中,其邻接点域的值为i的结点的个数是顶点vi的入度.
显然,上述算法的时间复杂度是O(n+e).值得注意的是,一个图的邻接矩阵表示是唯一的,而其邻接表表示则不唯一。
这是因为邻接表表示中各表结点的链接顺序取决于建立邻接表的算法以及各边的输入次序。
在邻接表中要判定任意两个顶点vi和vj之间是否有边或弧相连,需要遍历第i个或第j个单链表,不象邻接矩阵那样能方便地对顶点进行随机访问.因此,对于图来说使用邻接矩阵或邻接表作存储结构各有其利弊。
构造一个具有n个顶点和e条边的无向网的时间复杂度为O(n2+e*n),其中O(n2)用于对邻
接矩阵初始化.
三各功能的程序流程
1.函数功能的实现
1)图的建立及输出
图的邻接表表示法类似于树的孩子链表表示法。
对于图G中的每个顶点vi,该方法把所有邻接于vi的顶点vj链成一个带头
结点的单链表,这个单链表就称为顶点vi的邻接表(AdjacencyList)。
[1].邻接表的结点结构
(1)表结点结构
┌────┬───┐
│adjvex│next│
└────┴───┘
邻接表中每个表结点均有两个域:
1邻接点域adjvex存放与vi相邻接的顶点vj的序号j。
2②链域next,将邻接表的所有表结点链在一起。
注意:
若要表示边上的信息(如权值),则在表结点中还应增加一个数据域。
(2)头结点结构
┌────┬─────┐
│vertex│firstedge│
└────┴─────┘
顶点vi邻接表的头结点包含两个域:
①顶点域vertex存放顶点vi的信息
②指针域firstedge存放vi的邻接表的头指针。
①为了便于随机访问任一顶点的邻接表,将所有头结点顺序存储在一个向量中就构成了图的邻接表表示。
②有时希望增加对图的顶点数及边数等属性的描述,可将邻接表和这些属性放在一起来描述图的存储结构。
2).无向图的邻接表
对于无向图,vi的邻接表中每个表结点都对应于与vi相关联的一条边。
因此,将邻接表的表头向量称为顶点表.将无向图的
邻接表称为边表.
【例】对于无向图G5,其邻接表表示如下面所示,其中顶点v0的边表上三个表结点中的顶点序号分别为1、2和3,它们分别表示
关联于v0的三条边(v0,v1),(v0,v2)和(v0,v3).
n个顶点e条边的无向图的邻接表表示中有n个顶点表结点和2e个边表结点.
3).有向图的邻接表
对于有向图,vi的邻接表中每个表结点都对应于以vi为始点射出的一条边。
因此,将有向图的邻接表称为出边表.
【例】有向图G6的邻接表表示如下面(a)图所示,其中顶点v1的邻接表上两个表结点中的顶点序号分别为0和4,它们分别表示从
v1射出的两条边(简称为v1的出边):
〈v1,v0〉和〈v1,v4〉.
n个顶点e条边的有向图,它的邻接表表示中有n个顶点表结点和e个边表结点。
4).有向图的逆邻接表
在有向图中,为图中每个顶点vi建立一个入边表的方法称逆邻接表表示法.
入边表中的每个表结点均对应一条以vi为终点(即射入vi)的边。
【例】G6的逆邻表如上面(b)图所示,其中v0的人边表上两个表结点1和3分别表示射人v0的两条边(简称为v0的入边):
〈v1,v0>
和〈v3,v0>
n个顶点e条边的有向图,它的接表表示中有n个顶点表结点和e个边表结点。
图的存储表示方法很多本节介绍两种最常用的方法邻接矩阵表示法和领接表表示法。
2变量的定义
Adjvex
Int
该弧所指向顶点的位置
Nextrac
StructArcNode指针
指向下条弧的指针
Info
该弧的权值
Data
顶点信息
Firstarc
指向第一条依附该顶点的弧的指针
Vexnum
图当前的顶点数
Arcnum
Int
图当前的弧数
四主函数的程序流程
五实验数据分析
实验数据分析:
首先,正常进入程序执行界面,显示输出如下:
=======================
=======1、创建邻接表图======
=======2、输出邻接表图======
=======3、退出===========
======================
请选择操作:
为了建立邻接表图,在此我们选择“1”,出现以下提示:
请正确创建邻接表图:
请输入图的顶点数目:
为了执行方便,我们输入一个顶点数目为4的邻接表。
之后便会提示“请输入图的弧的数目:
”,我们也输入4。
定义时,我们有typedefstructArcNode/{intadjvex;
/structArcNode*nextarc;
intinfo;
}ArcNode;
数据域包括三个域,除了结点和弧外还有弧的权值域,所以定义函数时定义了弧的权值,之后的提示就会有“请确认是否输入权值<
y/n>
:
"
在此我们选择Y,以后输入结点信息完之后输入弧的权值,接下来输入结点和弧的信息。
提示如下:
请输入弧尾[1,4]:
请输入弧头[1,4]:
请输入弧的权值:
在此我们输入(125),(136),(347),(418)。
接下来,程序会出现创建图成功的标志“CreateALGraphsuccess!
到此为止,图的创建完成。
此外,如果在输入结点和弧信息不合法的时候,程序不会继续往下执行,会要求用户再次输入结点信息和弧的信息,直到用户输入完全正确为止.
接下来进入第二阶段,重新选择操作.根据程序开始的提示,现在我们输入2,来查看我们的程序执行结果:
输出该邻接矩阵图如下:
======================
0110
0000
0001
1000
该图输出完毕!
请选择操作:
程序执行到此,又进入主菜单进行选择,图的输出流程到此完毕。
按3键可退出程序,按1键可再次进入建立图的程序流程,按2键可输出建立的图。
程序运行图如图1-1和图1—2:
图1—1图的建立
图1-2图的输出
六附源代码
#definemax20
#include<
malloc.h>
#include〈iostream>
usingnamespacestd;
typedefstructArcNode//定义表结点
{intadjvex;
//该弧所指向顶点的位置
structArcNode*nextarc;
//指向下一条弧的指针
//该弧的权值
}ArcNode;
typedefstructVNode//定义头结点
{intdata;
//顶点信息
//指向第一条依附该顶点的弧的指针
}VNode,AdjList[max];
typedefstruct//定义ALGraph
{AdjListvertices;
intvexnum,arcnum;
//图的当前顶点数和弧数
intkind;
//图的种类标志
}ALGraph;
voidCreateDG(ALGraph&G)//创建邻接表的图
{intk,i,j;
chartag;
cout〈<
”请输入图的顶点数目:
〈<
endl;
//输入顶点数目
cin〉〉G.vexnum;
cout<
<
”请输入图的弧的数目:
”〈<
endl;
//输入弧的数目
cin〉〉G。
arcnum;
”请确认是否输入弧的权值(y/n):
〈endl;
cin>
>
tag;
for(i=1;
i<
=G.vexnum;
++i)
{G。
vertices[i]。
data=i;
//初始化顶点值
G.vertices[i].firstarc=NULL;
//初始化指针
}
请输入弧的相关信息arc(V1--〉V2)”<
//构造弧
for(k=1;
k〈=G。
++k)
{cout〈<
endl<
〈"
请输入弧尾"
〈〈"
[1,"
〈〈G.vexnum<
〈”]:
;
〉i;
cout〈〈”请输入弧头”<
[1,"
”]:
;
cin〉〉j;
while(i<
1||i〉G。
vexnum||j〈1||j>
G。
vexnum)//如果弧头或弧尾