实验十三 图的基本操作—邻接表存储结构
图的基本操作(邻接表)
标头.h#include<math.h>#include<io.h>#include<process.h>#include<iostream>#define TRUE 1#define FLASE 0#define OK 1#define ERROR 0#define FALSE 0#define INFINITY INT_MAX//无穷大typedef int status;#define MAX_VERTEX_NUM 20#define MAX_NAME 5#define MAX_INFO 20typedef int VRType;typedef int InfoType;typedef char VertexType[MAX_NAME];enum GraphKind{DG,DN,AG,AN};// 有向图,有向网,无向图,无向图struct ArcNode{int adjvex; //该弧所指向的顶点的位置ArcNode *nextarc;//指向吓下一条弧的指针InfoType *info;//网的权值指针};//表结点typedef struct{VertexType data;//顶点信息ArcNode *firstarc;//第一个表结点的地址,指向第一条依附该顶点的弧的指针}VNode,AdjList[MAX_VERTEX_NUM]; //头结点struct ALGraph{AdjList vertices;int vexnum,arcnum;//图的当前顶点数和弧数int kind; //图的种类标志};int LocateVex(ALGraph G,VertexType u){//初始条件:图G存在,u和G中顶点有相同的特征//操作结果:若G中存在顶点u,则返回该顶点在图中的位置;否则返回-1int i;for(i=0;i<G.vexnum;++i)if(strcmp(u,G.vertices[i].data)==0)return i;return -1;}status CreateGraph(ALGraph &G){//采用邻接表存储结构,构造没有相关信息的图G(用一个函数构造四种图)int i,j,k;int w;//权值VertexType va ,vb;ArcNode *p;printf("请输入图的类型(有向图:0,有向网:1,无向图:2无向网:3)");scanf("%d",&G.kind);printf("请输入图的顶点数和边数");scanf("%d%d",&G.vexnum,&G.arcnum);printf("请输入%d个顶点的值(<%d个字符):\n",G.vexnum,MAX_NAME);for(i=0;i<G.vexnum;i++)//构造顶点向量{scanf("%s",G.vertices[i].data);G.vertices[i].firstarc=NULL;}if(G.kind==1||G.kind==3)//网printf("请顺序输入每条弧的权值,弧尾和弧头(以空格作为间隔):\n");else//图printf("请顺序输入每条边的弧尾和弧头(以空格作间隔):\n");for(k=0;k<G.arcnum;++k){if(G.kind==1||G.kind==3)//网scanf("%d%s%s",&w,va,vb);elsescanf("%s%s",va,vb);i=LocateVex(G,va);//弧尾j=LocateVex(G,vb);//弧头p=(ArcNode*)malloc(sizeof(ArcNode));p->adjvex=j;if(G.kind==1||G.kind==3)//网{p->info=(int*)malloc(sizeof(ArcNode));*(p->info)=w;}elsep->info=NULL;//图p->nextarc=G.vertices[i].firstarc;//插在表头G.vertices[i].firstarc=p;if(G.kind>=2)//无向图或网,产生第二个表结点{p=(ArcNode*)malloc(sizeof(ArcNode));p->adjvex=i;if(G.kind==3)//无向网{p->info=(int*)malloc(sizeof(int));*(p->info)=w;}elsep->info=NULL;//无向图p->nextarc=G.vertices[j].firstarc;G.vertices[j].firstarc=p;}}return OK;}void DestroyGraph(ALGraph &G){//初始条件:图G存在。
图的邻接表存储结构实验报告
《图的邻接表存储结构实验报告》1.需解决的的问题利用邻接表存储结果,设计一种图。
2.数据结构的定义typedef struct node{//边表结点int adj;//边表结点数据域struct node *next;}node;typedef struct vnode{//顶点表结点char name[20];node *fnext;}vnode,AList[M];typedef struct{AList List;//邻接表int v,e;//顶点树和边数}*Graph;3.程序的结构图4.函数的功能1)建立无向邻接表Graph Create1( )//建立无向邻接表{Graph G;int i,j,k;node *s;G=malloc(M*sizeof(vnode));printf("输入图的顶点数和边数:");scanf("%d%d",&G->v,&G->e);//读入顶点数和边数for(i=0;i<G->v;i++)//建立顶点表{ printf("请输入图第%d个元素:",i+1);scanf("%s",&G->List[i].name);//读入顶点信息G->List[i].fnext=NULL;//边表置为空表}for(k=0;k<G->e;k++)//建立边表--建立了2倍边的结点{ printf("请输入边的两顶点序号:(从0考试)");scanf("%d%d",&i,&j);//读入边(Vi,Vj)的顶点对序号s=(node *)malloc(sizeof(node));//生成边表结点s->adj=j;s->next=G->List[i].fnext;G->List[i].fnext=s;//将新结点*s插入顶点Vi的边表头部s=(node *)malloc(sizeof(node));s->adj=i;//邻接点序号为is->next=G->List[j].fnext;G->List[j].fnext=s;// 将新结点*s插入顶点Vj的边表头部}return G;}2)建立有向邻接图Graph Create2() //有向邻接图{Graph G;int i,j,k;node *q;G=malloc(M*sizeof(vnode));printf("请输入顶点数和弧数:");scanf("%d%d",&G->v,&G->e);for (i=0;i<G->v;i++) //建立有n个顶点的顶点表{ printf("请输入图第%d个元素:",i+1);scanf("%s",&G->List[i].name); //读入顶点信息G->List[i].fnext=NULL;}for (k=0;k<G->e;k++) //建立边表{ printf("请输入两顶点的序号:(从0开始)");scanf("%d%d",&i,&j);q=(node *)malloc(sizeof(node)); //生成新边表结点sq->adj=j; //邻接点序号为jq->next=G->List[i].fnext;G->List[i].fnext=q;}return G;}3)输出无向图的邻接表void Print1(Graph G)//输出无向图的邻接表{int i;node *p;printf("\n\t\t\t邻接表\n");for(i=0;i<G->v;i++){ p=G->List[i].fnext;printf("\t\t\t%d | %3s",i,G->List[i].name);while(p){printf("->%d",p->adj);p=p->next;}printf("\n");}}4)输出个元素的度数void Du(Graph G)//输出各元素的度数{int i,j;node *p;printf("\n\t\t\t各点度数\n");for(i=0;i<G->v;i++){ p=G->List[i].fnext;printf("\t\t\t顶点%2s的度为:",G->List[i].name);j=0;while(p){ j++;p=p->next;}printf("%d\n",j);}}5)返回图结点在的序号int LocateVex(Graph G,char *u){//初始条件:图G存在,u和G中顶点有相同的特征//操作结果:若G中存在顶点u,则返回该顶点在图中的位置;否则返回-1 int i;for(i=0;i<G->v;++i)if(strcmp(u,G->List[i].name)==0)return -1;}6)返回序号为v的图结点的值char *VertexGet(Graph G,int v){if(v>=G->v||v<0)exit(0);return G->List[v].name;}7)返回图结点v的第一个邻接顶点的序号int FirstAdjVex(Graph G,char *v){//初始条件:图G存在,v是G中的某个顶点//操作结果:返回v中第一个邻接顶点的序号。
图的邻接表存储方式.
图的邻接表存储方式——数组实现初探焦作市外国语中学岳卫华在图论中,图的存储结构最常用的就是就是邻接表和邻接矩阵。
一旦顶点的个数超过5000,邻接矩阵就会“爆掉”空间,那么就只能用邻接表来存储。
比如noip09的第三题,如果想过掉全部数据,就必须用邻接表来存储。
但是,在平时的教学中,发现用动态的链表来实现邻接表实现时,跟踪调试很困难,一些学生于是就觉得邻接表的存储方式很困难。
经过查找资料,发现,其实完全可以用静态的数组来实现邻接表。
本文就是对这种方式进行探讨。
我们知道,邻接表是用一个一维数组来存储顶点,并由顶点来扩展和其相邻的边。
具体表示如下图:其相应的类型定义如下:typepoint=^node;node=recordv:integer; //另一个顶点next:point; //下一条边end;vara:array[1..maxv]of point;而用数组实现邻接表,则需要定义两个数组:一个是顶点数组,一个是边集数组。
顶点编号结点相临边的总数s第一条邻接边next此边的另一邻接点边权值下一个邻接边对于上图来说,具体的邻接表就是:由上图我们可以知道,和编号为1的顶点相邻的有3条边,第一条边在边集数组里的编号是5,而和编号为5同一个顶点的下条边的编号为3,再往下的边的编号是1,那么和顶点1相邻的3条边的编号分别就是5,3,1。
同理和顶点3相邻的3条边的编号分别是11,8,4。
如果理解数组表示邻接表的原理,那么实现就很容易了。
类型定义如下:见图的代码和动态邻接表类似:下面提供一道例题邀请卡分发deliver.pas/c/cpp 【题目描述】AMS公司决定在元旦之夜举办一个盛大展览会,将广泛邀请各方人士参加。
现在公司决定在该城市中的每个汽车站派一名员工向过往的行人分发邀请卡。
但是,该城市的交通系统非常特别,每条公共汽车线路都是单向的,且只包含两个车站,即起点站与终点站,汽车从起点到终点站后空车返回。
数据结构图的存储结构及基本操作
数据结构图的存储结构及基本操作数据结构图的存储结构及基本操作1·引言数据结构图是一种用来描述数据元素之间关系的图形结构,它可以表示实体之间的联系和依赖关系。
本文将介绍数据结构图的存储结构及基本操作。
2·存储结构2·1 邻接矩阵邻接矩阵是使用二维数组来表示数据结构图中各个节点之间的关系。
矩阵的行和列代表节点,如果两个节点之间存在边,则矩阵相应位置的值为1,否则为0。
2·2 邻接表邻接表是使用链表来表示数据结构图中各个节点之间的关系。
每个节点都有一个链表,链表中的每个元素表示与该节点相邻的节点。
2·3 十字链表十字链表是使用链表来表示数据结构图中各个节点之间的关系。
每个节点都有两个链表,一个表示该节点指向的节点,另一个表示指向该节点的节点。
2·4 邻接多重表邻接多重表是使用链表来表示数据结构图中各个节点之间的关系。
每个节点都有一个链表,链表中的每个元素表示与该节点相邻的边。
3·基本操作3·1 创建图创建一个空的数据结构图,根据需要选择适当的存储结构。
3·2 插入节点在数据结构图中插入一个节点,并建立与其他节点的关系。
3·3 删除节点从数据结构图中删除一个节点,并删除与其他节点的关系。
3·4 插入边在数据结构图中插入一条边,连接两个节点。
3·5 删除边从数据结构图中删除一条边,断开两个节点的连接。
3·6 遍历图按照某种规则遍历整个数据结构图,访问每个节点。
本文档涉及附件:无本文所涉及的法律名词及注释:1·邻接矩阵:用于表示图的存储结构,矩阵的行和列代表图的节点,矩阵的值表示节点之间的连接关系。
2·邻接表:用于表示图的存储结构,每个节点都有一个链表,链表中的每个元素表示与该节点相邻的节点。
3·十字链表:用于表示图的存储结构,每个节点都有两个链表,一个表示该节点指向的节点,另一个表示指向该节点的节点。
计算机数据结构知识点梳理 图的存储及基本操作
(3)对于无向图,邻接矩阵的第i行(或第i列)非零元素(或非∞元素)的个数 正好是第i个顶点的度TD(vi)。
(4)对于有向图,邻接矩阵的第i行(或第i列)非零元素(或非∞元素)的 个数正好是第i个顶点的出度OD(vi)(或入度ID(vi))。
34 ^ ^
4、
无 向 图 的 邻 接 多 重 表
例a
b
c
d
e
1a 2b 3c 4d
5e
1
2
3
2
5
2^
1 ^4 ^
3
4
3 ^5 ^
[题1] n个顶点的无向图的邻接表中边表结点总数最多有( )。 A. 2n B. n C. n/2 D. n(n-1) 分析:n个顶点的无向图最多有n(n-1)/2条边,在无向图的邻接表中,每条边对应两个边
知识点12:图的存储及基本操作
1、邻接矩阵:就是用一维数组存储图中顶点的信息,用矩阵表示图中各顶点之 间的邻接关系(邻接矩阵的形式描述)。
(1) 无向图的邻接矩阵一定是一个对称矩阵。在不考虑压缩的情况下,邻接矩 阵的大小n2,考虑压缩的情况下,存放邻接矩阵时只需存放上(或下)三角矩 阵的元素即可,又由于主对角线为0,则至少需要n(n-1)/2 空间。
(1)若无向图中有n 个顶点、e条边,则它的邻接表需n个头结点和2e个表结 点。稀疏图用邻接表表示比邻接矩阵节省存储空间,当和边相关的信息较多 时更是如此。
(2)在无向图的邻接表中,顶点vi的度恰为第i个链表中的结点数;在有向图中,第i 个链表中的结点个数只是顶点vi的出度,为求入度,必须遍历整个邻接表。在所有 链表中其邻接点域的值为i的结点的个数是顶点vi的入度。
图的邻接表存储实现及深度优先遍历
第四次实验报告图的邻接表存储实现及深度优先遍历学号0708140119 电子072 姓名陆萍萍一、问题描述1、程序所能达到的基本功能构建以邻接表形式存储的表及实现深度优先遍历并输出结果。
2、输入的形式和输入值的范围:根据提示进行输入:先输入要构建的表的结点数和边数,要求是整型;输入各结点的代号,这里用char型,也可在源程序中改变其它形式;输入各边的头结点和尾结点的代号;3、输出的形式若正常输入,则输出深度优先遍历的最后结果。
用各结点的代码表示。
测试数据要求第一组数据:结点数和边数:4 4结点名称:a b c d边:a-b a-c b-c c-d 输出a-b-c-d-over!第二组数据:图如下:输出a-b-c-d-e-f-g-over! 4、概要设计1、抽象数据类型,它们的作用//图的结点类template<class T>class TVex{};//图类template<class T>class Graph{}//链表存储2主程序流程及模块调用关系(1)主程序模块:void main{构造一个图,对T实例化(char)。
调用Graph中的Create函数;调用Graph中的DFS函数;}(22、核心算法的粗线条伪码5、详细设计(要求主要变量和语句加注释)1、抽象数据类型的实现:包括类型定义和各个操作的实现。
1)TVex的详细设计(1)私有数据类型的定义private:T m_elem;TLinklist<int> m_arcs;2)Graph的详细设计(1)私有数据类型的定义private:TVex<T> Vextex[maxnum];int vexnum;int arcnum;int kind;int symbol[maxnum];(2)公有函数成员的定义Graph();void Create();int LocateVex(T v);void DFS();void DFS_IN(int i);(3)具体实现★template<class T>void Graph<T>::Create(){T v1,v2;int i,j;cout<<"*********************基本信息*****************************"<<endl;cout<<"请分别输入结点数和边数: ";cin>>vexnum>>arcnum;cout<<"***********************结点***************************"<<endl;for(int l=0;l<vexnum;l++){cout<<"请输入第"<<l+1<<"个结点的代号 ";cin>>Vextex[l].m_elem;}cout<<"***********************边数***************************"<<endl;for(int k=0;k<arcnum;k++){cout<<"请输入第"<<k+1<<"边的头结点和尾结点 ";cin>>v1>>v2;i=LocateVex(v1);j=LocateVex(v2);Vextex[i].m_arcs.InsertLate(j);Vextex[j].m_arcs.InsertLate(i);}cout<<"************************结果**************************"<<endl; }★template<class T>int Graph<T>::LocateVex(T v){for(int i=0;i<vexnum&&Vextex[i].m_elem!=v;i++); if(i==vexnum)return -1;elsereturn i;}★template<class T>void Graph<T>::DFS(){DFS_IN(0);cout<<"over!"<<endl;}★template<class T>void Graph<T>::DFS_IN(int i){int index;symbol[i]=1;cout<<Vextex[i].m_elem<<"-->";for(int j=0;;j++){index=Vextex[i].m_arcs.GetElem(j+1);if(index!=-1){if(symbol[index]!=1)DFS_IN(index);}elsebreak;}}2、其他主要算法的实现将次要算法均设为Graph的公有函数成员3、主程序的实现Void main(){huffmanTree<char> h;int *ww,n;char *cc;cout<<"请输入叶子节点的个数:";cin>>n;ww=new int[n];cc=new char[n];cout<<"请依次输入节点名称和权重:"<<endl;for(int i=1;i<=n;i++){cout<<"第"<<i<<"个"<<endl;cout<<" 名称:";cin>>cc[i-1];cout<<" 权重: ";cin>>ww[i-1];}h.CreatehuffmanTree(cc,ww,n);h.huffmanTreecoding();}四 .调试分析1、设计与调试过程中遇到的问题及分析、体会(1)这个实验较简单,经过对书本上已经给出的c版程序的分析,很容易就写出了对整个实验的大体思路。
关于图的存储方法(静态邻接表、前向星、边集数组)
关于图的存储⽅法(静态邻接表、前向星、边集数组)⼀、邻接矩阵(不多说了) G[u][v]⼆、邻接表1、动态链表(指针)⼀个数组表头(u)+ struct结点(v),相链,若有权值等信息再在结点⾥加相应域。
2、静态链表(数组) first数组(模拟表头、u)+ 边集数组(编号e,u、v)+ next数组(模拟指针相指)。
这个跟1看似有点区别(前者链的是点,后者链的是边),其实是没区别,因为要⽤数组实现链表,所以对1中所有结点实⾏e编号,意义就是“边”。
通常实现⽅法:开五个数组 first[MAXN]; u[MAXM], v[MAXM], w[MAXM], next[MAXM]。
三、边集数组就是把所有边放在⼀个数组⾥,这样就可以完成遍历所有边的操作了(很⼟吧= =)。
通常要根据实际需要做⼀些辅助储存。
1、上⾯的数组实现邻接表就是边集数组再加上first数组和next数组。
2、前向星。
跟1很相似的,区别是他对边集数组按u点(前⼀个端点)升序排序,使得由同⼀个点出发的边都集中在⼀起了。
再加上辅助数组 f[MAXN](跟前⾯first数组类似的作⽤),存结点i 出发的第⼀个边在边集数组⾥的位置。
所以注意到,前向星其实就是做了⼀个紧缩存储的处理,并且通过⼀次排序,省掉了next数组(静态邻接表)。
当然也可以不排序,多维护⼀个next数组。
通常实现⽅法:开四个数组 f[MAXN]; u[MAXM], v[MAXM], w[MAXM]。
附:①静态邻接表+Dijkstra+heap// Dijkstra+静态邻接表#include<cstdio>#include<cstring>#include<iostream>#include<queue>using namespace std;#define MAXN 100#define MAXM 100#define INF 1<<30typedef pair<int, int> pii; //(dist[v], v)priority_queue<pii, vector<pii>, greater<pii> > q;int first[MAXN];int u[MAXM], v[MAXM], w[MAXM], next[MAXM];int dist[MAXN], ins[MAXN]; // ins[] 是否在s集合中int n, m;void dijkstra(int st){for(int i=0; i<n; i++) dist[i] = i==st? 0: INF;memset(ins, 0, sizeof(ins));q.push(make_pair(dist[st], st));// ins[st] = 1; //别跟spfa inq弄混,在优先队列⾥取出来才算是ins了while(!q.empty()){pii p = q.top(); q.pop();int x = p.second;if(!ins[x]){ins[x] = 1;for(int i=first[x]; i!=-1; i=next[i]){if(dist[v[i]] > dist[x]+w[i]) //relax{dist[v[i]] = dist[x] + w[i];q.push(make_pair(dist[v[i]], v[i]));}}}}//end of while}void read_graph(){scanf("%d%d", &n, &m);memset(first, -1, sizeof(first));for(int i=0; i<m; i++){scanf("%d%d%d", &u[i], &v[i], &w[i]);next[i] = first[u[i]];first[u[i]] = i;}}int main(){read_graph();int st;dijkstra(scanf("%d", &st));for(int i=0; i<n; i++){printf("[%d,%d]=%d\n", st, i, dist[i]);}}②静态邻接表+spfa#include<cstdio>#include<cstring>#include<iostream>#include<queue>using namespace std;#define MAXN 100#define MAXM 100#define INF 1<<30queue<int> q;int first[MAXN], next[MAXM];struct edge{int u, v, w;}a[MAXM];int dist[MAXN], inq[MAXN];int n, m;void spfa(int st){for(int i=0; i<n; i++) dist[i] = i==st? 0: INF;memset(inq, 0, sizeof(inq));q.push(st);inq[st] = 1; //反正马上就出队,这个inq可以不要 while(!q.empty()){int u = q.front(); q.pop();inq[u] = 0;for(int e=first[u]; e!=-1; e=next[e]){int v = a[e].v;if(dist[v] > dist[u]+a[e].w){dist[v] = dist[u]+a[e].w;if(!inq[v]) { q.push(v); inq[v] = 1; } //inq=1}}}}void read_graph(){cin>>n>>m;memset(first, -1, sizeof(first)); //别忘了初始化表头 for(int e=0; e<m; e++){cin>>a[e].u>>a[e].v>>a[e].w;next[e] = first[a[e].u];first[a[e].u] = e;}}int main(){read_graph();int st;cin>>st;spfa(st);for(int i=0; i<n; i++){printf("[%d,%d]=%d\n", st, i, dist[i]);}}。
图-存储结构-邻接表
图-存储结构-邻接表⽂字描述 邻接表是图的⼀种链式存储结构。
在邻接表中,对图中每个顶点建⽴⼀个单链表,第i个单链表的结点表⽰依附顶点vi的边(对有向图是指以顶点vi为尾的弧)。
单链表中的每个结点由3个域组成,其中邻接点域adjvex指⽰与顶点vi邻接的点在图中的位置;链域nextarc指⽰下⼀条边或弧的结点;数据域info存储和边或弧相关的信息如权值等。
每个链表上附设⼀个表头结点,在表头结点中,除了设有链域firstarc指向链表中第⼀个结点外,还设有存储顶点vi的名或其他有关信息的数据域data。
在⽆向图的邻接表中,顶点vi的度恰为第i个单链表中的结点数;⽽在有向图中,第i个链表中的结点数只是顶点vi的出度,为求⼊度,需便历整个邻接表;为了⽅便确定顶点的⼊度或以顶点vi为头的弧,可以建⽴⼀个有向图的逆邻接表,即对每个顶点vi建⽴⼀个了链接以vi为头的弧的表。
⽰意图算法分析 在建⽴邻接表或逆邻接表时,若输⼊的顶点信息就是顶点的编号,则建⽴邻接表的时间复杂度为n+e;否则,需要通过查找才能得到顶点在图中位置,则时间复杂度为n*e. 在邻接表上容易找到任⼀顶点的第⼀个邻接点和下⼀个领接点,但要判定任意两个顶点(vi和vj)之间是否有边或弧相连,则需搜索第i个或第j个链表;因此,不及邻接矩阵⽅便。
代码实现1/*2以邻接表作为图的存储结构创建图。
3*/45 #include <stdio.h>6 #include <stdlib.h>7 #include <string.h>89#define INFINITY 100000 //最⼤值10#define MAX_VERTEX_NUM 20 //最⼤顶点数11#define None -112 typedef enum {DG, DN, UDG, UDN} GraphKind; //{有向图,有向⽹,⽆向图,⽆向⽹}13 typedef char VertexType;14 typedef struct{15char note[10];16 }InfoType;17//表结点18 typedef struct ArcNode{19int adjvex; //该弧所指向的顶点的位置20struct ArcNode *nextarc; //指向下⼀条弧的指针21 InfoType *info; //该弧相关信息的指针22 }ArcNode;23//头结点24 typedef struct VNode{25 VertexType data;//顶点信息26 ArcNode *firstarc;//指向第⼀条依附该顶点的弧的指针27 }VNode, AdjList[MAX_VERTEX_NUM];28 typedef struct{29 AdjList vertices;30int vexnum;//图的顶点数31int arcnum;//图的弧数32int kind; //图的种类标志33 }ALGraph;3435/*36若G中存在顶点u,则返回该顶点在图中位置;否则返回-1。
实现图的邻接矩阵和邻接表存储
实现图的邻接矩阵和邻接表存储1.需求分析对于下图所示的有向图G,编写一个程序完成如下功能:1.建立G的邻接矩阵并输出之2.由G的邻接矩阵产生邻接表并输出之3.再由2的邻接表产生对应的邻接矩阵并输出之2.系统设计1.图的抽象数据类型定义:ADT Graph{数据对象V:V是具有相同特性的数据元素的集合,称为顶点集数据关系R:R={VR}VR={<v,w>|v,w∈V且P(v,w),<v,w>表示从v到w的弧,谓词P(v,w)定义了弧<v,w>的意义或信息}基本操作P:CreatGraph(&G,V,VR)初始条件:V是图的顶点集,VR是图中弧的集合操作结果:按V和VR的定义构造图GDestroyGraph(&G)初始条件:图G存在操作结果:销毁图GInsertVex(&G,v)初始条件:图G存在,v和图中顶点有相同特征操作结果:在图G中增添新顶点v……InsertArc(&G,v,w)初始条件:图G存在,v和w是G中两个顶点操作结果:在G中增添弧<v,w>,若G是无向的则还增添对称弧<w,v>……DFSTraverse(G,Visit())初始条件:图G存在,Visit是顶点的应用函数操作结果:对图进行深度优先遍历,在遍历过程中对每个顶点调用函数Visit一次且仅一次。
一旦Visit()失败,则操作失败BFSTraverse(G,Visit())初始条件:图G存在,Visit是顶点的应用函数操作结果:对图进行广度优先遍历,在遍历过程中对每个顶点调用函数Visit一次且仅一次。
一旦Visit()失败,则操作失败}ADT Graph2.主程序的流程:调用CreateMG函数创建邻接矩阵M;调用PrintMatrix函数输出邻接矩阵M调用CreateMGtoDN函数,由邻接矩阵M创建邻接表G调用PrintDN函数输出邻接表G调用CreateDNtoMG函数,由邻接表M创建邻接矩阵N调用PrintMatrix函数输出邻接矩阵N3.函数关系调用图:3.调试分析(1)在MGraph的定义中有枚举类型typedefenum{DG,DN,UDG,UDN}GraphKind;dj);printf("输入相应权值:\n");for(i=0;i<;i++)for(j=0;j<;j++)if[i][j].adj){scanf("%d",&[i][j].info);}}typedef struct ArcNode{int adjvex;ata);printf("\n弧:\n");for(i=0;i<;++i){p=[i].firstarc;while(p){printf("%d→%d(%d)\t",i,p->adjvex,p->info); p=p->nextarc;}printf("\n");}ata=[i];[i].firstarc=NULL;dj==1){p=(ArcNode*)malloc(sizeof(ArcNode));p->adjvex=j;p->nextarc=[i].firstarc;p->info=[i][j].info;[i].firstarc=p;}}void CreateDNtoMG(MGraph &M,ALGraph G){int i,j;ArcNode *p;=GraphKind;=;=;for(i=0;i<;++i)[i]=[i].data;for(i=0;i<;++i){p=[i].firstarc;while(p){[i][p->adjvex].adj=1;p=p->nextarc;}dj!=1)[i][j].adj=0;}dj);printf("\n");}}void main(){MGraph M,N;ALGraph G;CreateMG(M);PrintMatrix(M);CreateMGtoDN(G,M);PrintDN(G);CreateDNtoMG(N,G);PrintMatrix(N);}。
11.图的邻接表存储实现
/*---------------------------------------------------------操作目的: 在图G中求顶点v的第一个邻接顶点 初始条件: 图G已存在 操作结果: 返回顶点v的第一个邻接顶点,若v无邻接顶点,则返回0 函数参数: ALGraph G 图G int v 待求顶点v 返回值: int 顶点v的第一个邻接顶点 ----------------------------------------------------------*/ int FirstAdjVex(ALGraph G, int v) { } /*---------------------------------------------------------操作目的: 在图G中求顶点v的相对于w的下一个邻接顶点 初始条件: 图G已存在 操作结果:返回顶点v的相对于w的下一个邻接顶点,若w是v的最后一个邻接顶点 则返回0 函数参数: ALGraph G 图G int v 待求顶点v int w v的一个邻接顶点 返回值: int 顶点v的相对于w的下一个邻接顶点 ----------------------------------------------------------*/ int NextAdjVex(ALGraph G, int v, int w) { } /*---------------------------------------------------------操作目的: 在图G中增加新顶点v 初始条件: 图G已存在,v和图G中的顶点具有相同类型 操作结果: 在图G中增加新顶点v 函数参数: ALGraph *G 图G ElemType v 待增加的新顶点v 返回值: 无 ----------------------------------------------------------*/ void InsertVex(ALGraph *G, ElemType v) { } /*----------------------------------------------------------
图的存储方式:邻接矩阵和邻接表【基础】
// 顶点数 边数
char vexs[max_vexNum];
// 顶点向量
double arcs[max_vexNum][max_vexNum]; // 邻接矩阵
}Graph;
5)基于邻接矩阵创建图 - CreateGraph()
1. 输入图的类型Kind,0--有向图,2--无向图; 2. 输入顶点数G.vexnum和边数G.arcnum; 3. 输入n个顶点,填入顶点数组G.vexs; 4. 输入边的偶对(vi,vj)或<vi,vj>, 填写邻接矩阵G.arcs
for (int i = 0; i < G.vex_num;i++) {
for (int j = 0; j < G.vex_num; j++) {
read_in >> G.arcs[i][j];
// calculate the arc_num if (G.arcs[i][j] > 0) {
G.arc_num++; } } }
// 顶点向量
double arcs[max_vexNum][max_vexNum]; // 邻接矩阵
}Graph;
2. 文件读取的方式,本程序采用文件流的方式进行数据的读写,相关代码如下:
#include <fstream>
ifstream read_in; read_in.open("L:\\Coding\\图的常见操作\\图的常见操作\\city_10.txt"); if (!read_in.is_open()) {
cout<<"文件读取失败."<<endl; return; }
数据结构-邻接表存储及遍历-课程设计-实验报告
数据结构-邻接表存储及遍历-课程设计-实验报告数据结构课程设计设计题目:邻接表存储及遍历学生姓名:专业班级:指导教师:完成时间:目录第一章需求分析 01.1 图 01.2 邻接表的概念 01.3邻接表的表示法 0第二章概要分析 (1)2.1 无向图 (1)2.2 有相图 (1)2.3 无向图 (1)2.4有向图 (1)第三章详细分析 (2)3.1 邻接表的建立 (2)3.2 邻接表的建立过程如下: (2)3.2.1无向图邻接表的建立 (2)3.2.2 有向图邻接表的建立 (3)3.3 邻接表的输出过程如下: (4)3.4 邻接表的遍历 (4)3.4.1 连通图的深度优先搜索遍历 (4)3.4.2 有向图的广度优先搜索遍历 (5)3.5 流程图 (6)3.5.1 主流程图 (6)3.5.2 无向图邻接表的流程图 (6)3.5.3 有向图邻接表的流程图 (10)第四章测试分析 (13)4.1 无向图 (14)4.1.1 主程序main()编写如下: (14)4.1.2 运行步骤 (16)4.2 有向图 (18)第五章心得体会 (20)第六章、参考文献 (20)第一章需求分析1.1 图①若图1.1②若图1.1v2图1.11.2 邻接表的概念对于图1.1中的每个顶点vi,该方法把所有邻接于vi的顶点vj链成一个单链表,这个单链表就称为顶点vi的邻接表。
1.3邻接表的表示法邻接表中每个表结点均有2个域,其一是邻接点域(adjvex),用以存放与vi 相邻接的顶点vj的序号;其二是链域(next),用来将邻接表的所有表结点链在一起。
并且为每个顶点vi的邻接表设置一个具有2个域的表头结点:一个是顶点域(vertex),用来存放顶点vi的信息;另一个是指针域(link),用于存入指向vi 的邻接表中第一个表结点的头指针。
第二章概要分析2.1 无向图无向图邻接表的建立,无向图邻接表的输出,无向图邻接表的深度优先搜索遍历,无向图邻接表的广度优先搜索遍历。
图的两种存储方式---邻接矩阵和邻接表
图的两种存储⽅式---邻接矩阵和邻接表图:图是⼀种数据结构,由顶点的有穷⾮空集合和顶点之间边的集合组成,表⽰为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),保存顶点的数组,保存边的数组。
数据结构实验 图的邻接表和邻接矩阵操作
p->weight=weight; p->nextarc=G.vertices[vv].firstarc; G.vertices[vv].firstarc=p; strcmp(G.vertices[vv].data,v);
q=(ArcNode *)malloc(sizeof(ArcNode)); q->adjvex=vv; q->weight=weight; q->nextarc=G.vertices[ww].firstarc; G.vertices[ww].firstarc=q; strcmp(G.vertices[ww].data,w);
实验报告 6
课程 数据结构 实验名称 图的建立及遍历
第页
专业
班级_ __ 学号_ ___ 姓名
实验日期: 2010 年 11 月 23 日
评分
一 、实验目的
1.学会用邻接矩阵和邻接表实现图结构和对图的基本操作。 2.掌握对图操作的具体实现; 3. 掌握图的两种遍历算法(深度优先、广度优先); 4、掌握求图的最小生成树和顶点间最短路径的算法;
int adjvex;//该弧指向的顶点的位置 ArcType weight; struct ArcNode *nextarc;//指向下一条弧指针 //InfoType *info;该弧相关信息的指针 }ArcNode; typedef struct VNode { VertexType data;//顶点信息 ArcNode *firstarc;//指向第一条依附该顶点的弧的指针 }VNode,AdjList[MAX_VEX_NUM]; typedef struct { AdjList vertices; int vexnum,arcnum; GraphKind kind; }ALGraph; ALGraph G; struct MiniSpanTree_Flag { VertexType adjvex; ArcType lowcost; }closedge[MAX_VEX_NUM]; typedef bool PathMatrix[MAX_VEX_NUM][MAX_VEX_NUM];
实验报告:图的存储结构和遍历
武汉东湖学院
实验报告
学院:计算机科学学院专业计算机科学与技术2016年11月18日
姓名付磊学号2015040131042
班级计科一班指导老师吴佳芬
课程名称数据结构成
绩
实验名称图的存储结构和遍历
1.实验目的
(1)了解邻接矩阵存储法和邻接表存储法的实现过程。
(2)了解图的深度优先遍历和广度优先遍历的实现过程。
2.实验内容
1. 采用图的邻接矩阵存储方法,实现下图的邻接矩阵存储,并输出该矩阵.
2. 设计一个将第1小题中的邻接矩阵转换为邻接表的算法,并设计一个在屏幕上显示邻接表的算法
3. 实现基于第2小题中邻接表的深度优先遍历算法,并输出遍历序列
4. 实现基于第2小题中邻接表的广度优先遍历算法,并输出遍历序列
3.实验环境
Visual C++ 6.0
4.实验方法和步骤(含设计)
我们通过二维数组中的值来表示图中节点与节点的关系。
通过上图可知,其邻接矩阵示意图为如下:
V0 v1 v2 v3 v4 v5
V0 0 1 0 1 0 1
V1 1 0 1 1 1 0
V2 0 1 0 0 1 0
V3 1 1 0 0 1 1
V4 0 1 1 1 0 0
V5 1 0 0 1 0 0
此时的“1”表示这两个节点有关系,“0”表示这两个节点无关系。
我们通过邻接表来在计算机中存储图时,其邻接表存储图如下:
}。
数据结构图的存储结构及基本操作
数据结构图的存储结构及基本操作一、数据结构图的存储结构数据结构图是一种表示数据元素之间关系的图形结构,常用于描述实体之间的关系、网络拓扑结构等。
数据结构图的存储结构可以使用邻接矩阵、邻接表等方式进行表示。
1.邻接矩阵存储结构邻接矩阵是使用二维数组表示数据结构图的存储结构。
数组的行和列分别代表数据结构图中的顶点,矩阵中的元素表示对应顶点之间的关系。
例如,如果顶点i和顶点j之间存在边,则邻接矩阵中(i,j)位置的元素为1;否则为0。
邻接矩阵的优点是可以快速判断两个顶点之间是否存在边,但缺点是当图中顶点较多时,矩阵中大部分元素为0,造成空间浪费。
2.邻接表存储结构邻接表是使用链表表示数据结构图的存储结构。
每个顶点对应一个链表,链表中的节点表示与该顶点直接相连的其他顶点。
顶点的链表可以使用数组或链表等数据结构来表示。
邻接表的优点是可以有效地利用存储空间,只存储存在边的关系,不存储无关边的信息。
但缺点是判断两个顶点之间是否存在边需要遍历链表,时间复杂度较高。
二、数据结构图的基本操作1.创建数据结构图创建数据结构图的操作是初始化一个空的图结构,可以选择使用邻接矩阵或邻接表存储结构。
根据实际需求,可以根据顶点和边的信息逐个添加到图结构中。
2.添加顶点添加顶点是向数据结构图中增加一个新的顶点,可以根据实际需求给顶点赋予相应的值或标识。
添加顶点的操作需要更新邻接矩阵或邻接表的相应位置。
3.添加边添加边是在两个已存在的顶点之间建立连接关系。
根据实际需求,可以指定边的权重或其他属性。
添加边的操作需要更新邻接矩阵或邻接表的相应位置。
4.删除顶点删除顶点是将一个存在的顶点从图结构中移除,同时将与该顶点相关的边也一并删除。
删除顶点的操作需要更新邻接矩阵或邻接表的相应位置。
5.删除边删除边是在两个已存在的顶点之间断开连接关系。
删除边的操作需要更新邻接矩阵或邻接表的相应位置。
6.查找顶点查找顶点是根据给定的值或标识在图结构中查找相应的顶点。
图的存储实验报告
图的存储实验报告图的存储实验报告引言在计算机科学领域中,图是一种重要的数据结构,用于描述对象之间的关系。
图的存储方式对于图的遍历、搜索和其他操作有着重要的影响。
本实验旨在探究不同的图存储方式,并比较它们在不同操作下的性能差异。
一、邻接矩阵存储方式邻接矩阵是一种常见的图存储方式,它使用二维数组来表示图中各个顶点之间的关系。
在邻接矩阵中,行和列分别代表图中的顶点,矩阵中的元素表示两个顶点之间的边的关系。
实验中,我们通过一个简单的例子来说明邻接矩阵的存储方式。
假设有一个无向图,其中包含5个顶点和6条边。
我们可以使用一个5x5的矩阵来表示这个图,矩阵中的元素为1表示两个顶点之间存在边,为0表示不存在边。
邻接矩阵的优点是可以快速判断两个顶点之间是否存在边,时间复杂度为O(1)。
然而,邻接矩阵的缺点是当图中的边数较少时,会造成存储空间的浪费。
此外,在图中顶点的增加和删除操作时,需要重新调整矩阵的大小,开销较大。
二、邻接表存储方式邻接表是另一种常见的图存储方式,它使用链表来表示图中各个顶点之间的关系。
在邻接表中,每个顶点都有一个链表,链表中存储了与该顶点相邻的顶点。
实验中,我们同样以一个简单的例子来说明邻接表的存储方式。
假设有一个有向图,其中包含4个顶点和5条边。
我们可以使用一个包含4个链表的数组来表示这个图,数组中的每个元素表示一个顶点,链表中的元素表示与该顶点相邻的顶点。
邻接表的优点是在图中边的数量较少时,可以节省存储空间。
此外,在图中顶点的增加和删除操作时,开销较小。
然而,邻接表的缺点是判断两个顶点之间是否存在边的时间复杂度较高,需要遍历链表,时间复杂度为O(顶点的度数)。
三、性能比较与结论通过实验,我们对比了邻接矩阵和邻接表两种图存储方式在不同操作下的性能差异。
在判断两个顶点之间是否存在边的操作中,邻接矩阵的时间复杂度为O(1),而邻接表的时间复杂度为O(顶点的度数)。
因此,在此操作下,邻接矩阵的性能更优。
邻接表
数据结构实验:图的邻接表表示实验目的邻接表(Adjancency List)是图的一种链式存储结构。
在邻接表中,学会对图的每个顶点建立一个单链表。
实验原理VR表示两个顶点之间的关系的集合。
若<v,w>∈VR,则<v,w>表示从v到w的一条弧(Arc),v称为弧尾(Tail),w成为弧头(Head)。
此时的图成为有向图。
若<v,w>∈VR必有<w,v>∈VR,则以无序的(v,w)表示这两个有序对,表示v和w间的一条边(Edge),此时的图成为无向图。
创建有向图:对读入的每一条弧,根据弧的弧尾部,在相应的邻接表的表头中添加该弧。
创建无向图:对读入的每一天边,分别在起点和终点对应的邻接表的表头中添加该边。
输出图:对于每个顶点对应的邻接表,遍历该链表,输出该顶点的邻接点。
#include<stdio.h>const int MAX_SIZE=20;typedef struct ArcNode{int adjvex;//邻接点int value;//权值struct ArcNode* nextarc;//下个节点指针};typedef struct VNode{int data;//顶点信息ArcNode *firstarc;//邻接表表头指针}VNode,AdjList[MAX_SIZE];typedef struct{AdjList vertices;//邻接表数组int vexnum,arcnum;//顶点数和边数int kind;//图种类}ALGraph;void CreateALGraph(ALGraph &algraph)//创建图函数{int i,head,tail,value;ArcNode * p,*q;printf("输入图的种类:(0---无向图1---有向图):");scanf("%d",&algraph.kind);printf("输入顶点数:");scanf("%d",&algraph.vexnum);printf("输入边数:");scanf("%d",&algraph.arcnum);//初始化图for(i=0;i<MAX_SIZE;i++){algraph.vertices[i].data=i;algraph.vertices[i].firstarc=NULL;}printf("输入边集:(head tail value)\n");for(i=0;i<algraph.arcnum;i++){scanf("%d%d%d",&head,&tail,&value);//生成新节点p=new ArcNode;p->adjvex=tail;p->value=value;if(algraph.vertices[head].firstarc==NULL) //表头为空{algraph.vertices[head].firstarc=p;p->nextarc=NULL;}else //表头非空{ p->nextarc=algraph.vertices[head].firstarc;algraph.vertices[head].firstarc=p;}//无向图if(algraph.kind==0){q=new ArcNode;q->adjvex=head;q->value=value;if(algraph.vertices[tail].firstarc==NULL){algraph.vertices[tail].firstarc=q;q->nextarc=NULL;}else{q->nextarc=algraph.vertices[tail].firstarc;algraph.vertices[tail].firstarc=q;}} //end(kind==0)}//end for};void PrintALGraph(const ALGraph &algraph)//输出图{if(algraph.kind==0)printf("\n无向图:\n");elseprintf("\n有向图\n");for(int i=0;i<algraph.vexnum;i++){printf("顶点V%d的边集:{",algraph.vertices[i].data);ArcNode *p=algraph.vertices[i].firstarc;//用p 指向每个顶点边集的表头指针bool first=true;while(p!=NULL){if(!first)//输出格式控制printf(",");elsefirst=false;if(algraph.kind==0)printf("(%d,%d)%d",algraph.vertices[i].data,p->adjvex,p->value);elseprintf("<%d,%d>%d",algraph.vertices[i].data,p->adjvex,p->value);p=p->nextarc;//指向下个节点}printf("}\n\n");}}int main(){ALGraph algraph1,algraph2;CreateALGraph(algraph1);//创建有向图PrintALGraph(algraph1);//输出有向图CreateALGraph(algraph2);//创建无向图PrintALGraph(algraph2);//输出无向图return 0;}实验结果实验心得学会了邻接表的表示方法,内部原理,也可以参考着书本编出邻接表来。
【免费下载】实验十三 图的基本操作邻接表存储结构
无向有权图: 有向有权图:
对全部高中资料试卷电气设备,在安装过程中以及安装结束后进行高中资料试卷调整试验;通电检查所有设备高中资料电试力卷保相护互装作置用调与试相技互术关,系电,力根通保据过护生管高产线中工敷资艺设料高技试中术卷资,配料不置试仅技卷可术要以是求解指,决机对吊组电顶在气层进设配行备置继进不电行规保空范护载高与中带资负料荷试下卷高问总中题体资,配料而置试且时卷可,调保需控障要试各在验类最;管大对路限设习度备题内进到来行位确调。保整在机使管组其路高在敷中正设资常过料工程试况中卷下,安与要全过加,度强并工看且作护尽下关可都于能可管地以路缩正高小常中故工资障作料高;试中对卷资于连料继接试电管卷保口破护处坏进理范行高围整中,核资或对料者定试对值卷某,弯些审扁异核度常与固高校定中对盒资图位料纸置试,.卷保编工护写况层复进防杂行腐设自跨备动接与处地装理线置,弯高尤曲中其半资要径料避标试免高卷错等调误,试高要方中求案资技,料术编试交写5、卷底重电保。要气护管设设装线备备置敷4高、调动设中电试作技资气高,术料课中并3中试、件资且包卷管中料拒含试路调试绝线验敷试卷动槽方设技作、案技术,管以术来架及避等系免多统不项启必方动要式方高,案中为;资解对料决整试高套卷中启突语动然文过停电程机气中。课高因件中此中资,管料电壁试力薄卷高、电中接气资口设料不备试严进卷等行保问调护题试装,工置合作调理并试利且技用进术管行,线过要敷关求设运电技行力术高保。中护线资装缆料置敷试做设卷到原技准则术确:指灵在导活分。。线对对盒于于处调差,试动当过保不程护同中装电高置压中高回资中路料资交试料叉卷试时技卷,术调应问试采题技用,术金作是属为指隔调发板试电进人机行员一隔,变开需压处要器理在组;事在同前发一掌生线握内槽图部内 纸故,资障强料时电、,回设需路备要须制进同造行时厂外切家部断出电习具源题高高电中中源资资,料料线试试缆卷卷敷试切设验除完报从毕告而,与采要相用进关高行技中检术资查资料和料试检,卷测并主处且要理了保。解护现装场置设。备高中资料试卷布置情况与有关高中资料试卷电气系统接线等情况,然后根据规范与规程规定,制定设备调试高中资料试卷方案。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
浙江大学城市学院实验报告课程名称数据结构基础实验项目名称实验十三图的基本操作—邻接表存储结构学生姓名专业班级学号实验成绩指导老师(签名)日期2015-1-15一.实验目的和要求1、掌握图的存储结构:邻接表。
2、学会对图的存储结构进行基本操作。
二.实验内容1、图的邻接表的定义及实现:建立头文件AdjLink.h,在该文件中定义图的邻接表存储结构,并编写图的初始化、建立图、输出图、输出图的每个顶点的度等基本操作实现函数。
同时在主函数文件test5_2.cpp中调用这些函数进行验证。
2、选做:编写图的深度优先遍历函数与广度优先遍历函数,要求把这两个函数添加到头文件AdjLink.h中,并在主函数文件test5_2.cpp中添加相应语句进行测试。
3、填写实验报告,实验报告文件取名为report13.doc。
4、上传实验报告文件report13.doc及源程序文件test5_2.cpp、AdjLink.h到Ftp服务器上自己的文件夹下。
三. 函数的功能说明及算法思路(包括每个函数的功能说明,及一些重要函数的算法实现思路)邻接表表示法的C语言描述:typedef struct Node{int adjvex; // 邻接点的位置WeightType weight; //权值域,根据需要设立struct Node *next; // 指向下一条边(弧)} edgenode; // 边结点typedef edgenode *adjlist[ MaxVertexNum ];//定义图的邻接表结构类型(没包含顶点信息)typedef struct{vexlist vexs; //顶点数据元素adjlist List; //边结点int n; //顶点数int k1,k2; //k1为有无向,k2为有无权}Adjlist;const int MaxVertexNum = 10; /*图的最大顶点数*/const int MaxEdgeNum = 100; /*图的最大边数*/const int MaxValue = 10000; /*无穷大的具体值*/typedef int WeightType; /*定义权的类型*/typedef char VertexType;typedef VertexType vexlist[MaxVertexNum]; /*定义顶点数组类型*/抽象数据类型:ADT Graph isData:一个邻接表,存储类型用adjlist表示Operations:void InitAdjoin(adjlist GL)//初始化函数void CreateAdjoin(adjlist GL,int n,char *s,int k1,int k2)//建立邻接表函数void PrintAdjoin( adjlist GL, int n, int k1, int k2)//把邻接表表示的图用顶点集和边集的形式输出的算法void PrintDegree(vexlist V,adjlist GL,int n,int k1)//输出图的每个顶点的度void dfsAdjoin(adjlist GL,int i,int n,bool *visited)//深度优先遍历函数 void bfsAdjoin(adjlist GL,int i,int n, bool *visited)//广度优先遍历end度的算法(PrintDegree):建立一个数组存放所以顶点的度,若为无向图,根据边缘结点的指针数组计算该结点的度;若为有向图,查找所有边缘结点的邻接点域,当前结点的度为该节点对应的度+1队列:typedef char ElemType;struct Queue{ElemType *queue;int front,rear;int MaxSize;};Operations:void InitQueue(Queue &Q) //初始化循环队列Qint EmptyQueue(Queue Q)//判断队列是否为空,空返回1,否则返回0void EnQueue(Queue &Q,ElemType item)// 入队列ElemType OutQueue(Queue &Q) // 出队列end Queue四. 实验结果与分析(包括运行结果截图、结果分析等)无向无权图:有向无权图:无向有权图:有向有权图:五. 心得体会该邻接表与上一个实验邻接矩阵差不多,做起来比较简单,只是将度的算法比较麻烦。
【附录----源程序】test5_2.cpp:#include<iostream.h>#include<stdio.h>#include<stdlib.h>#include<string.h>#include<strstrea.h>const int MaxVertexNum = 10; /*图的最大顶点数*/const int MaxEdgeNum = 100; /*图的最大边数*/const int MaxValue = 10000; /*无穷大的具体值*/typedef int WeightType; /*定义权的类型*/typedef char VertexType;typedef VertexType vexlist[MaxVertexNum]; /*定义顶点数组类型*/#include "AdjLink.h"void main(){Adjlist GL;//邻接表int i;cout<<"请输入图的顶点数:";cin>>GL.n;cout<<"请输入图的顶点集合(如:abc…)"<<endl;for(i=0; i<GL.n; i++)cin>>GL.vexs[i];cout<<"请输入图是否有向和是否无权选择(0为否,1为是) :";cin>>GL.k1>>GL.k2;bool *visited=new bool[GL.n]; //定义并动态分配标志数组InitAdjoin(GL.List);cout<<"输入图的边集:";char *a=new char[100];cin>>a;CreateAdjoin(GL.List,GL.n,a,GL.k1,GL.k2);PrintDegree(GL.vexs,GL.List,GL.n,GL.k1);cout<<"按图的邻接表得到的深度优先遍历序列:"<<endl;for(i=0;i<GL.n;i++) visited[i]=false;dfsAdjoin(GL.List,0,GL.n,visited);cout<<endl;cout<<"按图的邻接表得到的广度优先遍历序列:"<<endl;for(i=0;i<GL.n;i++) visited[i]=false;bfsAdjoin(GL.List,0,GL.n,visited);cout<<endl;PrintAdjoin(GL.List,GL.n,GL.k1,GL.k2);}AdjLink.h:typedef struct Node{int adjvex; // 邻接点的位置WeightType weight; //权值域,根据需要设立struct Node *next; // 指向下一条边(弧)} edgenode; // 边结点typedef edgenode *adjlist[ MaxVertexNum ];//定义图的邻接表结构类型(没包含顶点信息)typedef struct{vexlist vexs; //顶点数据元素adjlist List; //边结点int n; //顶点数int k1,k2; //k1为有无向,k2为有无权}Adjlist;void InitAdjoin(adjlist GL)//初始化函数{int i;for(i=0;i<MaxVertexNum;i++)GL[i] = NULL;}void CreateAdjoin(adjlist GL,int n,char *s,int k1,int k2)//建立邻接表函数{// n为顶点数。
k1=0 代表无向图否则为有向图,// k2 =0 代表无权图否则为带权图。
// s存放边集,如:{<2,3>3,<1,0>8,<2,0>6},{(2,3),(1,0),(2,0)}istrstream sin(s);char c1,c2,c3;int i, j;WeightType w;edgenode *p; //将指向新申请的边结点sin>>c1; //读入第一个字符‘{’if(k2==0) // 建立无权图do {sin>>c1>>i>>c2>>j>>c3;p = (edgenode *) malloc(sizeof(edgenode));p->adjvex=j; p->weight=1; //插入边结点p->next = GL[i]; GL[i] = p;if (k1==0) { //对无向图,需再插入一个边结点p = (edgenode *) malloc(sizeof(edgenode));p->adjvex=i; p->weight=1;p->next = GL[j];GL[j] = p;}sin>>c1; //读入‘,’或‘}’} while ( c1==',');else // 建立有权图do {sin>>c1>>i>>c2>>j>>c3>>w;p = (edgenode *) malloc(sizeof(edgenode));p->adjvex=j; p->weight=w; //插入边结点p->next = GL[i]; GL[i] = p;if (k1==0) { //对无向图,需再插入一个边结点p = (edgenode *) malloc(sizeof(edgenode));p->adjvex=i; p->weight=w;p->next = GL[j];GL[j] = p;}sin>>c1; //读入‘,’或‘}’} while ( c1==',' );}void PrintAdjoin( adjlist GL, int n, int k1, int k2)//把邻接表表示的图用顶点集和边集的形式输出的算法{// k1=0 代表无向图否则为有向图,// k2 =0 代表无权图否则为带权图int i, j;edgenode *p;cout<<" V={ "; //准备输出顶点集for (i=0; i<n-1; i++)cout<<i<<',';cout<<n-1<<'}'<<endl;cout<<" E={ "; //准备输出边集for (i=0; i<n; i++) {if(k2==0){ //无权图p=GL[i];while(p){ //输出顶点i 的邻接表j=p->adjvex;if(k1==0){ //无向图if (i<j)cout<<'('<<i<<','<<j<<')'<<',';}else //有向图cout<<'<'<<i<<','<<j<<'>'<<',';p=p->next;}}else{ //带权图p=GL[i];while(p){j=p->adjvex;if(k1==0){ //无向图if (i<j)cout<<'('<<i<<','<<j<<')'<<p->weight<<',';}else //有向图cout<<'<'<<i<<','<<j<<'>'<<p->weight<<',';p=p->next;}}} //forcout<<'}'<<endl;}void PrintDegree(vexlist V,adjlist GL,int n,int k1) //输出图的每个顶点的度{int i,j;int *d=new int[n];//存放结点的度的数组edgenode *p,*q;for(i=0;i<n;i++){d[i]=0;p=GL[i];while(p){d[i]++;p=p->next;}if(k1){for(j=0;j<n;j++){q=GL[j];while(q){if(q->adjvex==i)d[i]++;q=q->next;}}}cout<<V[i]<<"的度为"<<d[i]<<endl;}delete[] d;}/*===================选作部分================================*/ typedef char ElemType;struct Queue{ElemType *queue;int front,rear;int MaxSize;};void InitQueue(Queue &Q) //初始化循环队列Q{Q.MaxSize=10;Q.queue=(ElemType *)malloc(sizeof(ElemType)*Q.MaxSize);Q.rear=Q.front=0;}int EmptyQueue(Queue Q)//判断队列是否为空,空返回1,否则返回0{return Q.front==Q.rear;}void EnQueue(Queue &Q,ElemType item)// 入队列{if((Q.rear+1) % Q.MaxSize == Q.front){//若队列已满,重新分配2倍大的空间Q.queue=(ElemType *)realloc(Q.queue,2*Q.MaxSize*sizeof(ElemType));if(Q.rear != Q.MaxSize-1){ //原队列尾部内容向后移for(int i=0; i<=Q.rear; i++)Q.queue[i+Q.MaxSize] = Q.queue[i];Q.rear=Q.rear+Q.MaxSize;}Q.MaxSize=2*Q.MaxSize;}// 插入itemQ.rear=(Q.rear+1)%Q.MaxSize;Q.queue[Q.rear]=item;}ElemType OutQueue(Queue &Q) // 出队列{if(Q.front==Q.rear){ //若空队列,则结束运行cerr<< "队列已空,无法删除!" <<endl;exit(1);}//删除队头元素,并返回该元素Q.front=(Q.front +1)%Q.MaxSize;return Q.queue[Q.front];}void dfsAdjoin(adjlist GL,int i,int n,bool *visited)//深度优先遍历函数{ //从vi出发进行DFSint j;cout<<i<<' '; //访问顶点vivisited[i] = 1; //置访问标志edgenode *p=GL[i]; //取vi的第一个邻接点while(p != NULL){ //依次取vi的每个邻接点j = p->adjvex;if(!visited[j])dfsAdjoin(GL,j,n,visited);p=p->next;}}void bfsAdjoin(adjlist GL,int i,int n, bool *visited)//广度优先遍历{ //从vi出发进行BFSint k, j;Queue q;cout<<i<<' ';visited[i]=1;InitQueue(q);EnQueue(q,i);while(!EmptyQueue(q)){k= OutQueue (q);edgenode *p=GL[k]; //取vk的第一个邻接点while(p != NULL){ //依次取vk的每个邻接点j = p->adjvex;if(!visited[j]){cout<<j<<' ';visited[j] = 1;EnQueue (q, j);}p=p->next;}}}。