实现图的邻接矩阵和邻接表存储
- 格式:doc
- 大小:30.50 KB
- 文档页数:3
图的邻接矩阵和邻接表相互转换图的邻接矩阵存储方法具有如下几个特征:1)无向图的邻接矩阵一定是一个对称矩阵。
2)对于无向图的邻接矩阵的第i 行非零元素的个数正好是第i 个顶点的度()i v TD 。
3)对于有向图,邻接矩阵的第i 行非零元素的个数正好是第i 个顶点的出度()i v OD (或入度()i v ID )。
4)用邻接矩阵方法存储图,很容易确定图中任意两个顶点之间是否有边相连;但是,要确定图中有多少条边,则必须按行、按列对每个元素进行检测,所发费得时间代价大。
邻接表是图的一种顺序存储与链式存储相结合的存储方法。
若无向图中有n 个顶点、e 条边,则它的邻接表需n 个头结点和2e 个表结点。
显然,在边稀疏的情况下,用邻接表表示图比邻接矩阵存储空间。
在无向图的邻接表中,顶点i v 的度恰好是第i 个链表中的结点数,而在有向图中,第i 个链表中结点个数是顶点i v 的出度。
在建立邻接表或邻逆接表时,若输入的顶点信息即为顶点的编号,则建立临接表的时间复杂度是)(e n O +;否则,需要通过查找才能得到顶点在图中位置,则时间复杂度为)*(e n O 。
在邻接表上容易找到任意一顶点的第一个邻接点和下一个邻接点,但要判断任意两个顶点之间是否有边或弧,则需要搜索第i 个或第j 个链表,因此,不及邻接矩阵方便。
邻接矩阵和邻接表相互转换程序代码如下:#include<iostream.h>#define MAX 20//图的邻接表存储表示typedef struct ArcNode{int adjvex; //弧的邻接定点 char info; //邻接点值struct ArcNode *nextarc; //指向下一条弧的指针}ArcNode;typedef struct Vnode{ //节点信息char data;ArcNode *link;}Vnode,AdjList[MAX];typedef struct{AdjList vertices;int vexnum; //节点数int arcnum; //边数}ALGraph;//图的邻接矩阵存储表示typedef struct{int n; //顶点个数char vexs[MAX]; //定点信息int arcs[MAX][MAX]; //边信息矩阵}AdjMatrix;/***_____________________________________________________***///函数名:AdjListToMatrix(AdjList g1,AdjListMatrix &gm,int n)//参数:(传入)AdjList g1图的邻接表,(传入)int n顶点个数,(传出)AdjMatrix gm图的邻接矩阵//功能:把图的邻接表表示转换成图的邻接矩阵表示void AdjListToAdjMatrix(ALGraph gl,AdjMatrix &gm){int i,j,k;ArcNode *p;gm.n=gl.vexnum;for(k=0;k<gl.vexnum;k++)gm.vexs[k]=gl.vertices[k].data;for(i=0;i<MAX;i++)for(j=0;j<MAX;j++)gm.arcs[i][j]=0;for(i=0;i<gl.vexnum;i++){p=gl.vertices[i].link; //取第一个邻接顶点while(p!=NULL){ //取下一个邻接顶点gm.arcs[i][p->adjvex]=1;p=p->nextarc;}}}/***________________________________________________***///函数名:AdjMatrixToAdjListvoid AdjMatrixToAdjList(AdjMatrix gm,ALGraph &gl){int i,j,k,choice;ArcNode *p;k=0;gl.vexnum=gm.n;cout<<"请选择所建立的图形是无向图或是有向图:";cin>>choice;for(i=0;i<gm.n;i++){gl.vertices[i].data=gm.vexs[i];gl.vertices[i].link=NULL;}for(i=0;i<gm.n;i++)for(j=0;j<gm.n;j++)if(gm.arcs[i][j]==1){k++;p=new ArcNode;p->adjvex=j;p->info=gm.vexs[j];p->nextarc=gl.vertices[i].link;gl.vertices[i].link=p;}if(choice==1)k=k/2;gl.arcnum=k;}void CreateAdjList(ALGraph &G){int i,s,d,choice;ArcNode *p;cout<<"请选择所建立的图形是有向图或是无向图:";cin>>choice;cout<<"请输入节点数和边数:"<<endl;cin>>G.vexnum>>G.arcnum;for(i=0;i<G.vexnum;i++){cout<<"第"<<i<<"个节点的信息:";cin>>G.vertices[i].data;G.vertices[i].link=NULL;}if(choice==1){for(i=0;i<2*(G.vexnum);i++){cout<<"边----起点序号,终点序号:";cin>>s>>d;p=new ArcNode;p->adjvex=d;p->info=G.vertices[d].data;p->nextarc=G.vertices[s].link;G.vertices[s].link=p;}}else{for(i=0;i<G.vexnum;i++){cout<<"边----起点序号,终点序号:";cin>>s>>d;p=new ArcNode;p->adjvex=d;p->info=G.vertices[d].data;p->nextarc=G.vertices[s].link;G.vertices[s].link=p;}}}void CreateAdjMatrix(AdjMatrix &M){int i,j,k,choice;cout<<"请输入顶点个数:";cin>>M.n;cout<<"请输入如顶点信息:"<<endl;for(k=0;k<M.n;k++)cin>>M.vexs[k];cout<<"请选择所建立的图形是无向图或是有向图:";cin>>choice;cout<<"请输入边信息:"<<endl;for(i=0;i<M.n;i++)for(j=0;j<M.n;j++)M.arcs[i][j]=0;switch(choice){case 1:{for(k=0;k<M.n;k++){cin>>i>>j;M.arcs[i][j]=M.arcs[j][i]=1;}};break;case 2:{for(k=0;k<M.n;k++){cin>>i>>j;M.arcs[i][j]=1;}};break;}}void OutPutAdjList(ALGraph &G){int i;ArcNode *p;cout<<"图的邻接表如下:"<<endl;for(i=0;i<G.vexnum;i++){cout<<G.vertices[i].data;p=G.vertices[i].link;while(p!=NULL){cout<<"---->("<<p->adjvex<<" "<<p->info<<")";p=p->nextarc;}cout<<endl;}}void OutPutAdjMatrix(AdjMatrix gm){cout<<"图的邻接矩阵如下:"<<endl;for(int i=0;i<gm.n;i++){。
数据结构—统计有向图中每个顶点的出度和⼊度(以邻接矩阵和邻接表两种⼊式实现)⼊、邻接矩阵实现假设不带权有向图采⼊邻接矩阵 g 存储,设计实现以下功能的算法:(1)求出图中每个顶点的⼊度。
(2)求出图中每个顶点的出度。
(3)求出图中出度为 0 的顶点数。
#include#include#includeusing namespace std;#define INFINITY 65535#define MAX_VERTEX_NUM 100typedef char VertexType;typedef struct {VertexType vexs[MAX_VERTEX_NUM];顶点 //数组int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM];邻接矩 //阵int v, e; 图顶点//和边的数量} MGraph;int num=0;全局变量负责统计出度为 0 的顶点个数void CreateMGraph(MGraph &G){int i,j,k,w;printf("输⼊顶点数和边数:\n");scanf("%d%d",&G.v,&G.e);//for(i=0;iG.arcs[i][j]=INFINITY;初始化邻接//矩阵for(k=0;k{printf("输⼊边(i,j)上的下标 i,j 和权 w\n");scanf("%d%d%d",&i,&j,&w);G.arcs[i][j]=w;}}void indu(MGraph G){int n=0;printf("⼊度:\n");for(int i=0;i//scanf("%c",G.vexs[i]);for(i=0;i{for(int j=0;j} if(n==0) num++; printf("%d ",n); n=0; } } int main() { MGraph G; CreateMGraph(G); { indu(G); if(G.arcs[j][i]!=INFINITY) printf("\n"); n++; outdu(G); } printf("\n"); printf("%d ",n); printf("出度为 0 的顶点个数:%d",num); n=0; return 0; } } } #include#include#includeusing namespace std;#define INFINITY 65535#define MAX_VERTEX_NUM 100typedef int VertexType;int num=0;n++;⼊、邻接表void outdu(MGraph G) 要 不 //要加引⼊,有时候需要仔细考虑⼊下 { 假设不带权有向图采⼊邻接表 G 存储,设计实现以下功能的算法: int n=0;(1) 求出图中每个顶点的⼊度。
重庆邮电大学2022年[数据结构]考研真题一、选择题1.对于双向循环链表,每个结点有两个指针域next和prior,分别指向前驱和后继。
在p指针所指向的结点之后插入s指针所指结点的操作应为()。
A.p->next=s;s->prior=p;p->next->prior=s;s->next=p->next;B.p->next=s;p->next->prior=s;s->prior=p;s->next=p->next;C.s->prior=p;s->next=p->next;p->next=s;p->next->prior=s;D.s->prior=p;s->next=p->next;p->next->prior=s;p->next=s; 2.由abc,3个结点可以构造出多少种不同的二叉树?()A.2B.3C.4D.53. 设有数组A[i,j],数组的每个元素长度为3字节,i的值为1到8,j的值为1到10,数组从内存首地址BA开始顺序存放,当用以列为主存放时,元素A[5,8]的存储首地址为()。
A.BA+141B.BA+180C.BA+222D.BA+2254. 一个栈的输入序列为123,则下列序列中不可能是栈的输出序列的是()。
A.231B.321C.312D.1235. 下述编码中哪一个不是前缀码()。
A.(00,01,10,11)B.(0,1,00,11)C.(0,10,110,111)D.(1,01,000,001)6. 当一棵有n个结点的二叉树按层次从上到下,同层次从左到右将数据存放在一维数组A[l..n]中时,数组中第i个结点的左孩子为()。
A.A[2i](2i=<n)B.A[2i+1](2i+1=<n)C.A[i/2]D.无法确定7. 假设一个有n个顶点和e条弧的有向图用邻接表表示,则删除与某个顶点vi相关的所有弧的时间复杂度是()。
实验6.1实现图的存储和遍历一,实验目的掌握图的邻接矩阵和邻接表存储以及图的邻接矩阵存储的递归遍历。
二,实验内容6.1实现图的邻接矩阵和邻接表存储编写一个程序,实现图的相关运算,并在此基础上设计一个主程序,完成如下功能:(1)建立如教材图7.9所示的有向图G的邻接矩阵,并输出。
(2)由有向图G的邻接矩阵产生邻接表,并输出。
(3)再由(2)的邻接表产生对应的邻接矩阵,并输出。
6.2 实现图的遍历算法(4)在图G的邻接矩阵存储表示基础上,输出从顶点V1开始的深度优先遍历序列(递归算法)。
(5)利用非递归算法重解任务(4)。
(6)在图G的邻接表存储表示基础上,输出从顶点V1开始的广度优先遍历序列。
三,源代码及结果截图#include<stdio.h>#include<stdlib.h>#include<string.h>#include<iostream.h>#include<malloc.h>#define MAX_VERTEX_NUM 20typedef char VRType;typedef int InfoType; // 存放网的权值typedef char VertexType; // 字符串类型typedef enum{DG,DN,AG,AN}GraphKind; // {有向图,有向网,无向图,无向网}/*建立有向图的邻接矩阵*/typedef struct ArcCell{VRType adj;//VRType是顶点关系类型,对无权图用1或0表示是否相邻;对带权图则为权值类型InfoType *info; //该弧相关信息的指针(可无)}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];typedef struct{VertexType vexs[MAX_VERTEX_NUM];//顶点向量AdjMatrix arcs;//邻接矩阵int vexnum,arcnum;;//图的当前顶点数和弧数GraphKind kind;//图的种类标志}MGraph;/* 顶点在顶点向量中的定位*/int LocateVex(MGraph &M,VRType v1){int i;for(i=0;i<M.vexnum;i++)if(v1==M.vexs[i])return i;return -1;}void CreateGraph(MGraph &M)//建立有向图的邻接矩阵{int i,j,k,w;VRType v1,v2;M.kind=DN;printf("构造有向网:\n");printf("\n输入图的顶点数和边数(以空格作为间隔):");scanf("%d%d",&M.vexnum,&M.arcnum);printf("输入%d个顶点的值(字符):",M.vexnum);getchar();for(i=0;i<M.vexnum;i++) //输入顶点向量{scanf("%c",&M.vexs[i]);}printf("建立邻接矩阵:\n");for(i=0;i<M.vexnum;i++)for(j=0;j<M.vexnum;j++){M.arcs[i][j].adj=0;M.arcs[i][j].info=NULL;}printf("请顺序输入每条弧(边)的权值、弧尾和弧头(以空格作为间隔):\n");for(k=0;k<M.arcnum;++k)// 构造表结点链表{cin>>w>>v1>>v2;i=LocateVex(M,v1);j=LocateVex(M,v2);M.arcs[i][j].adj=w;}}//按邻接矩阵方式输出有向图void PrintGraph(MGraph M){int i,j;printf("\n输出邻接矩阵:\n");for(i=0; i<M.vexnum; i++){printf("%10c",M.vexs[i]);for(j=0; j<M.vexnum; j++)printf("%2d",M.arcs[i][j].adj);printf("\n");}}// 图的邻接表存储表示typedef struct ArcNode{int adjvex; // 该弧所指向的顶点的位置struct ArcNode *nextarc; // 指向下一条弧的指针InfoType *info; // 网的权值指针)}ArcNode; // 表结点typedef struct VNode{VertexType data; // 顶点信息ArcNode *firstarc; // 第一个表结点的地址,指向第一条依附该顶点的弧的指针}VNode,AdjList[MAX_VERTEX_NUM];// 头结点typedef struct{AdjList vertices;int vexnum,arcnum; // 图的当前顶点数和弧数int kind; // 图的种类标志}ALGraph;void CreateMGtoDN(ALGraph &G,MGraph &M){//由有向图M的邻接矩阵产生邻接表int i,j;ArcNode *p;G.kind=M.kind;G.vexnum=M.vexnum;G.arcnum=M.arcnum;for(i=0;i<G.vexnum;++i){//构造表头向量G.vertices[i].data=M.vexs[i];G.vertices[i].firstarc=NULL;//初始化指针}for(i=0;i<G.vexnum;++i)for(j=0;j<G.vexnum;++j)if(M.arcs[i][j].adj){p=(ArcNode*)malloc(sizeof(ArcNode));p->adjvex=j;p->nextarc=G.vertices[i].firstarc;p->info=M.arcs[i][j].info;G.vertices[i].firstarc=p;}}void CreateDNtoMG(MGraph &M,ALGraph &G){ //由邻接表产生对应的邻接矩阵int i,j;ArcNode *p;M.kind=GraphKind(G.kind);M.vexnum=G.vexnum;M.arcnum=G.arcnum;for(i=0;i<M.vexnum;++i)M.vexs[i]=G.vertices[i].data;for(i=0;i<M.vexnum;++i){p=G.vertices[i].firstarc;while(p){M.arcs[i][p->adjvex].adj=1;p=p->nextarc;}//whilefor(j=0;j<M.vexnum;++j)if(M.arcs[i][j].adj!=1)M.arcs[i][j].adj=0;}//for}//输出邻接表void PrintDN(ALGraph G){int i;ArcNode *p;printf("\n输出邻接表:\n");printf("顶点:\n");for(i=0;i<G.vexnum;++i)printf("%2c",G.vertices[i].data);printf("\n弧:\n");for(i=0;i<G.vexnum;++i){p=G.vertices[i].firstarc;while(p){printf("%c→%c(%d)\t",G.vertices[i].data,G.vertices[p->adjvex].data,p->info);p=p->nextarc;}printf("\n");}//for}int visited[MAX_VERTEX_NUM]; // 访问标志数组(全局量)void(*VisitFunc)(char* v); // 函数变量(全局量)// 从第v个顶点出发递归地深度优先遍历图G。
邻接表和邻接矩阵
邻接表和邻接矩阵是表示图的两种常用数据结构,它们用于描述图中各个顶点之间的连接关系。
具体分析如下:
- 邻接表:邻接表是一种链表数组,其中每个数组元素对应一个顶点,并且包含一个链表,链表中的每个节点代表与该顶点相邻的顶点。
这种结构特别适合于表示稀疏图,即边的数量远小于顶点数量的平方的图。
在邻接表中,对于每个顶点,只需要存储与其直接相连的顶点,因此可以节省空间。
当图的顶点较多,且图为稀疏图时,邻接表通常是更合适的选择。
- 邻接矩阵:邻接矩阵是一种二维数组,其中行和列都代表图中的顶点。
如果两个顶点之间存在边,则相应的矩阵元素值为1(或者边的权重,如果是带权图),否则为0。
邻接矩阵适用于表示稠密图,即边的数量接近顶点数量的平方的图。
邻接矩阵的优点是可以快速地判断任意两个顶点之间是否存在边,但是当图非常稀疏时,它会占用较多的内存空间。
总的来说,邻接表和邻接矩阵各有优势,选择哪种数据结构取决于具体的应用场景。
如果图是稀疏的,并且需要节省存储空间,邻接表通常更合适;如果需要快速查询任意两点之间的关系,而图又相对稠密,邻接矩阵可能是更好的选择。
数据结构与算法课程设计报告课程设计题目:图的算法实现专业班级:信息与计算科学1002班目录摘要 (1)1、引言 (1)2、需求分析 (1)3、概要设计 (2)4、详细设计 (4)5、程序设计 (10)6、运行结果 (18)7、总结体会 (19)摘要(题目): 图的算法实现实验内容图的算法实现问题描述:(1)将图的信息建立文件;(2)从文件读入图的信息,建立邻接矩阵和邻接表;(3)实现Prim、Kruskal、Dijkstra和拓扑排序算法。
关键字:邻接矩阵、Dijkstra和拓扑排序算法1.引言本次数据结构课程设计共完成图的存储结构的建立、Prim、Kruskal、Dijkstra 和拓扑排序算法等问题。
通过本次课程设计,可以巩固和加深对数据结构的理解,通过上机和程序调试,加深对课本知识的理解和熟练实践操作。
(1)通过本课程的学习,能够熟练掌握数据结构中图的几种基本操作;(2)能针对给定题目,选择相应的数据结构,分析并设计算法,进而给出问题的正确求解过程并编写代码实现。
使用语言:CPrim算法思想:从连通网N={V,E}中的某一顶点v0出发,选择与它关联的具有最小权值的边(v0,v),将其顶点加入到生成树的顶点集合V中。
以后每一步从一个顶点在V中,而另一个顶点不在V中的各条边中选择权值最小的边(u,v),把它的顶点加入到集合V中。
如此继续下去,直到网中的所有顶点都加入到生成树顶点集合V中为止。
拓扑排序算法思想:1、从有向图中选取一个没有前驱的顶点,并输出之;2、从有向图中删去此顶点以及所有以它为尾的弧;重复上述两步,直至图空,或者图不空但找不到无前驱的顶点为止。
没有前驱-- 入度为零,删除顶点及以它为尾的弧-- 弧头顶点的入度减1。
2.需求分析1、通过键盘输入建立一个新的有向带权图,建立相应的文件;2、对建立的有向带权图进行处理,要求具有如下功能:(1)用邻接矩阵和邻接表的存储结构输出该有向带权图,并生成相应的输出结果;(2)用Prim、Kruskal算法实现对图的最小生成树的求解,并输出相应的输出结果;(3)用Dijkstra算法实现对图中从某个源点到其余各顶点的最短路径的求解,并输出相应的输出结果;(4)实现该图的拓扑排序算法。
分别以邻接矩阵和邻接表作为图的存储结构,给出连通图的深度优先遍历的递归算法算法思想:(1)访问出发点vi,并将其标记为已访问过。
(2)遍历vi的的每一个邻接点vj,若vi未曾访问过,则以vi为新的出发点继续进行深度优先遍历。
算法实现:Boolean visited[max]; // 访问标志数void DFS(Graph G, int v){ // 算法7.5从第v个顶点出发递归地深度优先遍历图Gint w;visited[v] = TRUE; printf("%d ",v); // 访问第v个顶点for (w=FirstAdjVex(G, v); w>=0; w=NextAdjVex(G, v, w)) if (!visited[w]) // 对v的尚未访问的邻接顶点w递归调用DFS DFS(G, w);}/*****************************************************/ /*以邻接矩阵作为存储结构*/DFS1(MGraph G,int i){int j;visited[i]=1;printf("%c",G.vexs[i]);for(j=1;j<=G.vexnum;j++)if(!visited[j]&&G.arcs[i][j]==1) DFS1(G,j);}/*以邻接表作为存储结构*/DFS2(ALGraph G,int i){int j;ArcPtr p;visited[i]=1;printf("%c",G.vertices[i].data);for(p=G.vertices[i].firstarc;p!=NULL;p=p->nextarc){j=p->adjvex;if(!visited[j]) DFS2(j);}}。
邻接矩阵和邻接表邻接矩阵与邻接表都是建立在图结构中的逻辑关系,用于存储图中相邻节点之间的连接关系,是用来表示网络的重要的数据结构,大量应用于无权图或带权图的表示、存储和操作。
一、邻接矩阵1.概念:邻接矩阵(Adjacency Matrix)是一种用来存储图G中顶点之间的关系的结构,它是由一个二维数组来表示的,数组中的每一行和每一列都代表一个顶点,而数组元素之间的值有一定含义,这些值代表了两个顶点之间是否存在连接,也就是说,只有存在边才能够表示值,否则以无穷大表示。
2.特点:(1)存储空间大:邻接矩阵是一个矩形数组,其中的每一行和每一列都代表一个顶点,那么它所占用的空间一定是与节点的度数有关的,因此在稀疏图结构中使用邻接矩阵对空间也会非常消耗;(2)查找方便:邻接矩阵存储的是节点两两之间的连接关系,只要矩阵中相应位置上的值不为无穷大,就能判断这两个节点之间是否存在连接,因此在查找图中某两节点之间连接关系的时候,邻接矩阵的效率会比较高。
二、邻接表1.概念:邻接表也是一种非常常用的表示图的数据结构,它采用的是链表的形式来存储顶点的相邻的结点的关系,也就是说,每个顶点都会有一个链表来存储它周围的结点。
它能够比较好的展示出图中各个顶点之间的关系,以及图中结点的孤立情况。
2.特点:(1)存储空间小:由于邻接表使用链表的方式存储节点,它可以精确的表示两个节点的距离,而非像邻接矩阵一样,数组中的每一行和每一列都代表一个节点,因此,它所占用的空间会比邻接矩阵小些,在内存空间中有比较大的空间优势;(2)查找速度略低:虽然邻接表能精确的表示两个节点之间的距离,而且只需要占用少量内存,但是查找两点之间连接关系所花费的时间会略大于邻接矩阵。
typedef struct{int adj;/*权值类型*/}arc;/*边*/typedef struct{node node[maxnode];arc arcs[maxnode][maxnode];}graph;void ins_arc(graph *g,int V,int W){g->arcs[V][W].adj=1;return;}void del_arc(graph *g,int V,int W){g->arcs[V][W].adj=0;return;}typedef struct st_arc{int adjvex; /*存放依附于该边的另一顶点在一维数组中的序号*/int weight; /*存放和该边有关的信息,如权值等*/struct st_arc *nextarc; /*依附于该顶点的下一个边结点的指针*/}arcnode; /*链式结构存储边信息*/typedef struct{int vertex; /*存放与顶点有关的信息*/struct st_arc *firstarc; /*指针域,存放与该顶点相邻接的所有顶点组成的单链表的头指针*/}vernode; /*存储顶点信息*/typedef vernode adjlist[maxnode];网上的程序参考:# include <stdio.h># include <stdlib.h># include <conio.h># define MAXLEN 10# define LARGE 999typedef struct {int a[MAXLEN],b[MAXLEN],w[MAXLEN]; /*第K边的起点,终点,权值*/char vexs[MAXLEN]; /*顶点信息集合*/ int vexnum,arcnum; /*顶点数和边数*/int kind; /*图的类型*/int arcs[MAXLEN][MAXLEN]; /*邻接矩阵*/}Graph;void printf_adjmatrix(Graph g) { /*输出邻接矩阵*/ int i,j;printf("邻接矩阵为:\n");printf("vertex\t");for (i=0;i<g.vexnum;i++) printf("%4c",g.vexs[i]);printf("\n");for(i=0;i<g.vexnum;i++) {printf("%4c \t",g.vexs[i]);for(j=0;j<g.vexnum;j++) printf("%4d",g.arcs[i][j]);printf("\n");}}void create_1(Graph *g) { /*建立有向图的邻接矩通过这个实验,我明白了图区别于树和链表的基本架构!。
第2讲图的存储结构——教学讲义本讲介绍4种较常用的存储表示法:①邻接矩阵表示法;②邻接表;③邻接多重表;④十字链表。
由于每种方法各有利弊,因此可以根据实际应用问题来选择合适的存储表示方法。
①邻接矩阵表示法图的邻接矩阵表示法(Adjacency Matrix)也称作数组表示法。
它采用两个数组来表示图:一个是用于存储顶点信息的一维数组,另一个是用于存储图中顶点之间关联关系的二维数组,这个关联关系数组被称为邻接矩阵。
若G是一具有n个顶点的无权图,G的邻接矩阵是具有如下性质的n×n矩阵A:上图所示G1和G2的邻接矩阵如下所示。
若图G是一个有n个顶点的网,则它的邻接矩阵是具有如下性质的n×n矩阵AA1=图G1,G2的邻接矩阵(a) G1是有向图(b) G2是无向图例如:下图就是一个有向网及其邻接矩阵的示例。
邻接矩阵表示法的C 语言描述如下:#define MAX_VERTEX_NUM 20 /*最多顶点个数*/#define INFINITY 32768 /*表示极大值,即∞*//* 图的种类:DG 表示有向图, DN 表示有向网, UDG 表示无向图, UDN 表示无向网 */typedef enum{DG, DN, UDG, UDN} GraphKind;typedef char VertexData; /*假设顶点数据为字符型*/ typedef struct ArcNode{AdjType adj; /* 对于无权图,用1或0表示是否相邻;对带权图,则为权值类型 */OtherInfo info; } ArcNode;typedef struct{VertexData vertex[MAX_VERTEX_NUM]; /*顶点向量*/ArcNode arcs [MAX_VERTEX_NUM][MAX_VERTEX_NUM]; /*邻接矩阵*/ int vexnum, arcnum; /*图的顶点数和弧数*/ GraphKind kind; /*图的种类标志*/ } AdjMatrix; /*(Adjacency Matrix Graph )*/邻接矩阵法的特点如下:● 存储空间: 对于无向图而言,它的邻接矩阵是对称矩阵(因为若(v i ,v j )∈E (G ),则(v j ,v i )∈E (G )),因此可以采用特殊矩阵的压缩存储法,即只存储其下三角即可,这样,一个具有n 个顶点的无向图G ,它的邻接矩阵需要n (n -1)/2个存储空间即可。
一、实验目的1. 理解邻接矩阵的概念及其在图论中的应用。
2. 掌握邻接矩阵的构建方法。
3. 学会使用邻接矩阵进行图的深度优先遍历和广度优先遍历。
4. 比较邻接矩阵和邻接表两种图的存储结构的优缺点。
二、实验内容1. 构建邻接矩阵2. 使用邻接矩阵进行图的深度优先遍历3. 使用邻接矩阵进行图的广度优先遍历4. 分析邻接矩阵和邻接表的优缺点三、实验环境1. 操作系统:Windows 102. 编程语言:C++3. 开发工具:Visual Studio 2019四、实验步骤1. 构建邻接矩阵(1)定义图的顶点数量n。
(2)创建一个nn的二维数组A,用于存储邻接矩阵。
(3)根据图的边信息,将对应的A[i][j]值设置为1(表示存在边)或0(表示不存在边)。
2. 使用邻接矩阵进行图的深度优先遍历(1)初始化访问标记数组visited,用于记录顶点是否被访问过。
(2)从某个顶点v开始,将其标记为已访问,并将其加入访问序列。
(3)对于v的每个邻接顶点u,如果u未被访问过,则递归调用深度优先遍历算法,并将u加入访问序列。
(4)重复步骤3,直到所有顶点都被访问过。
3. 使用邻接矩阵进行图的广度优先遍历(1)初始化队列Q和一个访问标记数组visited。
(2)将起始顶点v入队,并将其标记为已访问。
(3)当队列不为空时,执行以下步骤:a. 从队列中取出一个顶点v。
b. 将v的邻接顶点u入队,并将u标记为已访问。
c. 将v加入访问序列。
(4)重复步骤3,直到队列空为止。
4. 分析邻接矩阵和邻接表的优缺点(1)邻接矩阵的优点:a. 查找边的时间复杂度为O(1)。
b. 遍历图的时间复杂度为O(n^2)。
c. 适用于稠密图。
(2)邻接矩阵的缺点:a. 空间复杂度为O(n^2),对于稀疏图,空间利用率低。
b. 查找边和遍历图的时间复杂度较高。
(3)邻接表的优点:a. 空间复杂度为O(n+e),对于稀疏图,空间利用率高。
b. 查找边和遍历图的时间复杂度为O(n+e)。
图的两种存储⽅式---邻接矩阵和邻接表图:图是⼀种数据结构,由顶点的有穷⾮空集合和顶点之间边的集合组成,表⽰为G(V,E),V表⽰为顶点的集合,E表⽰为边的集合。
⾸先肯定是要对图进⾏存储,然后进⾏⼀系列的操作,下⾯对图的两种存储⽅式邻接矩阵和邻接表尽⾏介绍。
(⼀)、邻接矩阵存储:⽤两个数组分别进⾏存储数据元素(顶点)的信息和数据元素之间的关系(边或弧)的信息。
存储顶点:⽤⼀个连续的空间存储n个顶点。
存储顶点之间的边:将由n个顶点组成的边⽤⼀个n*n的矩阵来存储,如果两个顶点之间有边,则表⽰为1,否则表⽰为0。
下⾯⽤代码来实现邻接矩阵的存储:#define SIZE 10class Graph{public:Graph(){MaxVertices = SIZE;NumVertices = NumEdges = 0;VerticesList = new char[sizeof(char)*MaxVertices];Edge = new int*[sizeof(int*)*MaxVertices];int i,j;for(i = 0;i<MaxVertices;i++)Edge[i] = new int[sizeof(int)*MaxVertices];for(i = 0;i<MaxVertices;i++){for(j = 0;j<MaxVertices;++j)Edge[i][j] = 0;}}void ShowGraph(){int i,j;cout<<"";for(i = 0;i<NumVertices;i++)cout<<VerticesList[i]<<"";cout<<endl;for(i = 0;i<NumVertices;i++){cout<<VerticesList[i]<<"";for(j = 0;j<NumVertices;j++)cout<<Edge[i][j] <<"";cout<<endl;}cout<<endl;}int GetVertexPos(char v){int i;for(i = 0;i<NumVertices;i++){if(VerticesList[i] == v)return i;}return -1;}~Graph(){Destroy();}void Insert(char v){if(NumVertices < MaxVertices){VerticesList[NumVertices] = v;NumVertices++;}}void InsertEdge(char v1,char v2){int i,j;int p1 = GetVertexPos(v1);int p2 = GetVertexPos(v2);if(p1 == -1 || p2 == -1)return ;Edge[p1][p2] = Edge[p2][p1] = 1;NumEdges++;}void RemoveEdge(char v1,char v2){int p1 = GetVertexPos(v1);int p2 = GetVertexPos(v2);if(p1 == -1 || p2== -1)return;if(Edge[p1][p2] == 0)return;Edge[p1][p2] = Edge[p2][p1] = 0;NumEdges--;}void Destroy(){delete[] VerticesList;VerticesList = NULL;for(int i = 0;i<NumVertices;i++){delete Edge[i];Edge[i] = NULL;}delete[] Edge;Edge = NULL;MaxVertices = NumVertices = 0;}void RemoveVertex(char v){int i,j;int p = GetVertexPos(v);int reNum = 0;if(p == -1)return;for(i = p;i<NumVertices-1;i++){VerticesList[i] = VerticesList[i+1];}for(i = 0;i<NumVertices;i++){if(Edge[p][i] != 0)reNum++;}for(i = p;i<NumVertices-1;i++){for(j = 0;j<NumVertices;j++){Edge[i][j] = Edge[i+1][j];}}for(i = p;i<NumVertices;i++){for(j = 0;j<NumVertices;j++)Edge[j][i] = Edge[j][i+1];}NumVertices--;NumEdges = NumEdges - reNum;}private:int MaxVertices;int NumVertices;int NumEdges;char *VerticesList;int **Edge;};上⾯的类中的数据有定义最⼤的顶点的个数(MaxVertices),当前顶点的个数(NumVertices),当前边的个数(NumEdges),保存顶点的数组,保存边的数组。
数据结构图实验报告一、实验目的本次实验的主要目的是深入理解和掌握数据结构图的基本概念、原理和操作方法,通过实际编程和操作,提高对数据结构的应用能力和解决问题的能力。
二、实验环境本次实验使用的编程语言为C++,开发环境为Visual Studio 2019。
三、实验内容(一)线性表1、顺序表实现顺序表的创建、插入、删除、查找等基本操作。
分析顺序表在不同操作下的时间复杂度。
2、链表实现单链表、双向链表的创建、插入、删除、查找等基本操作。
比较单链表和双向链表在操作上的优缺点。
(二)栈和队列1、栈实现顺序栈和链式栈。
用栈解决表达式求值问题。
2、队列实现顺序队列和链式队列。
用队列模拟银行排队问题。
(三)树1、二叉树实现二叉树的创建、遍历(前序、中序、后序)。
计算二叉树的深度和节点数。
2、二叉搜索树实现二叉搜索树的插入、删除、查找操作。
分析二叉搜索树的性能。
(四)图1、图的存储实现邻接矩阵和邻接表两种图的存储方式。
比较两种存储方式的优缺点。
2、图的遍历实现深度优先遍历和广度优先遍历算法。
用图的遍历解决最短路径问题。
四、实验步骤(一)线性表1、顺序表定义一个数组来存储顺序表的元素,并使用一个变量记录当前表的长度。
插入操作时,需要判断插入位置是否合法,如果合法则将插入位置后的元素依次向后移动一位,然后将新元素插入指定位置。
删除操作时,先判断删除位置是否合法,合法则将删除位置后的元素依次向前移动一位,并更新表的长度。
查找操作通过遍历数组来实现。
分析不同操作的时间复杂度,插入和删除操作在最坏情况下为O(n),查找操作在平均情况下为 O(n/2)。
2、链表对于单链表,定义一个节点结构体,包含数据域和指向下一个节点的指针域。
通过操作指针来实现插入、删除和查找操作。
双向链表则在节点结构体中增加指向前一个节点的指针,使得操作更加灵活,但也增加了空间复杂度。
比较单链表和双向链表在插入、删除操作中指针的调整过程,得出双向链表在某些情况下更方便,但空间开销较大的结论。
#include<stdio.h>
#include<malloc.h>
#define MAXV 100
//以下定义邻接矩阵类型
typedef struct
{
int no; //顶点编号
int info; //顶点其余的信息
}VertexType;
typedef struct
{
int edges[MAXV][MAXV]; //邻接矩阵
int n,e; //顶点数,弧数
VertexType vexs[MAXV]; //存放顶点信息
}MGraph;
//一下定义邻接表类型
typedef struct ANode //弧的节点结构类型
{
int adjvex; //该弧的终点位置
struct ANode *nextarc;
int info; //弧的相关信息
} ArcNode;
typedef struct Vnode //邻接表头结点类型
{
int data; //顶点信息
ArcNode *firstarc; //指向第一条弧
}VNode;
typedef VNode AdjList[MAXV];
typedef struct
{
AdjList adjlist;
int n,e;
}ALGraph;
void MatToList(MGraph g,ALGraph *&G) //将邻接矩阵 g 转换为邻接表 G {
int i,j,n=g.n;
ArcNode *p;
G=(ALGraph *)malloc(sizeof(ALGraph));
for(i=0;i<n;i++)
G->adjlist[i].firstarc=NULL;
for(i=0;i<n;i++)
for(j=n-1;j>=0;j--)
if(g.edges[i][j])
{
p=(ArcNode *)malloc(sizeof(ArcNode));
p->adjvex=j;
p->info=g.edges[i][j];
p->nextarc=G->adjlist[i].firstarc;
G->adjlist[i].firstarc=p;
}
G->n=n;
G->e=g.e;
}
void ListToMat(ALGraph *G,MGraph &g) //邻接表G转换为邻接矩阵g {
int i,j,n=G->n;
ArcNode *p;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
g.edges[i][j]=0;
for(i=0;i<n;i++)
{
p=G->adjlist[i].firstarc;
while(p)
{
g.edges[i][p->adjvex]=p->info;
p=p->nextarc;
}
}
g.n=n;
g.e=G->e;
}
void DispMat(MGraph g) //输出邻接矩阵
{
int i,j;
for(i=0;i<g.n;i++)
{
for(j=0;j<g.n;j++)
if(g.edges[i][j])
printf("%3d",g.edges[i][j]);
else if(i==j)
printf("%3d",0);
else
printf("%3s","*");
printf("\n");
}
}
void DispAdj(ALGraph *G) //输出邻接表
{
int i;
ArcNode *p;
for(i=0;i<G->n;i++)
{
p=G->adjlist[i].firstarc;
if(p) printf("%3d:",i);
while(p)
{
printf("%3d",p->adjvex);
p=p->nextarc;
}
printf("\n");
}
}
int main()
{
int i,j;
MGraph g,g1;
ALGraph *G;
int A[MAXV][6]={
{0,5,0,7,0,0},
{0,0,4,0,0,0},
{8,0,0,0,0,9},
{0,0,5,0,0,6},
{0,0,0,5,0,0},
{3,0,0,0,1,0}
};
g.n=6; g.e=10;
for(i=0;i<g.n;i++)
for(j=0;j<g.n;j++)
g.edges[i][j]=A[i][j];
printf("\n");
printf("有向图G的邻接矩阵是:\n");
DispMat(g);
G=(ALGraph *)malloc(sizeof(ALGraph));
printf("图G的邻接矩阵转换成邻接表:\n"); MatToList(g,G);
DispAdj(G);
printf("图G的邻接表转换成邻接矩阵:\n"); ListToMat(G,g1);
DispMat(g1);
printf("\n");
return 0;
}。