无向图的邻接矩阵

合集下载

图的矩阵表示及习题-答案讲解

图的矩阵表示及习题-答案讲解

177图的矩阵表示图是用三重组定义的,可以用图形表示。

此外,还可以用矩阵表示。

使用矩阵表示图,有利于用代数的方法研究图的性质,也有利于使用计算机对图进行处理。

矩阵是研究图的重要工具之一。

本节主要讨论无向图和有向图的邻接矩阵、有向图的可达性矩阵、无向图的连通矩阵、无向图和有向图的完全关联矩阵。

定义9.4.1 设 G =<V ,E >是一个简单图,V =⎨v 1,v 2,…,v n ⎬ A (G )=(ij a ) n ×n其中:1j i v v v v a j i j i ij =⎩⎨⎧=无边或到有边到 i ,j =1,…,n称A (G )为G 的邻接矩阵。

简记为A 。

例如图9.22的邻接矩阵为:⎪⎪⎪⎪⎪⎭⎫⎝⎛=0111101011011010)(G A 又如图9.23(a)的邻接矩阵为:⎪⎪⎪⎪⎪⎭⎫⎝⎛=0001101111000010)(G A 由定义和以上两个例子容易看出邻接矩阵具有以下性质:①邻接矩阵的元素全是0或1。

这样的矩阵叫布尔矩阵。

邻接矩阵是布尔矩阵。

②无向图的邻接矩阵是对称阵,有向图的邻接矩阵不一定是对称阵。

178③邻接矩阵与结点在图中标定次序有关。

例如图9.23(a)的邻接矩阵是A (G ),若将图9.23(a)中的接点v 1和v 2的标定次序调换,得到图9.23(b),图9.23(b)的邻接矩阵是A ′(G )。

⎪⎪⎪⎪⎪⎭⎫⎝⎛='0010101100011100)(G A 考察A (G )和A ′(G )发现,先将A (G )的第一行与第二行对调,再将第一列与第二列对调可得到A ′(G )。

称A ′(G )与A (G )是置换等价的。

一般地说,把n 阶方阵A 的某些行对调,再把相应的列做同样的对调,得到一个新的n 阶方阵A ′,则称A ′与A 是置换等价的。

可以证明置换等价是n 阶布尔方阵集合上的等价关系。

虽然,对于同一个图,由于结点的标定次序不同,而得到不同的邻接矩阵,但是这些邻接矩阵是置换等价的。

图的邻接矩阵和邻接表相互转换

图的邻接矩阵和邻接表相互转换

图的邻接矩阵和邻接表相互转换图的邻接矩阵存储方法具有如下几个特征: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++){。

设计一个算法将无向图的邻接矩阵转为对应邻接表的算法

设计一个算法将无向图的邻接矩阵转为对应邻接表的算法

设计一个算法将无向图的邻接矩阵转为对应邻接表的算法-CAL-FENGHAI-(2020YEAR-YICAI)_JINGBIAN1.设计一个算法将无向图的邻接矩阵转为对应邻接表的算法。

typedef struct {int vertex[m]; int edge[m][m];}gadjmatrix;typedef struct node1{int info;int adjvertex; struct node1 *nextarc;}glinklistnode;typedef struct node2{int vertexinfo;glinklistnode *firstarc;}glinkheadnode;void adjmatrixtoadjlist(gadjmatrix g1[ ],glinkheadnode g2[ ]){int i,j; glinklistnode *p;for(i=0;i<=n-1;i++) g2[i].firstarc=0;for(i=0;i<=n-1;i++) for(j=0;j<=n-1;j++)if [i][j]==1){p=(glinklistnode *)malloc(sizeof(glinklistnode));p->adjvertex=j;p->nextarc=g[i].firstarc; g[i].firstarc=p;p=(glinklistnode *)malloc(sizeof(glinklistnode));p->adjvertex=i;p->nextarc=g[j].firstarc; g[j].firstarc=p;}}设计判断两个二叉树是否相同的算法。

typedef struct node {datatype data; struct node *lchild,*rchild;} bitree;int judgebitree(bitree *bt1,bitree *bt2){if (bt1==0 && bt2==0) return(1);else if (bt1==0 || bt2==0 ||bt1->data!=bt2->data) return(0);else return(judgebitree(bt1->lchild,bt2->lchild)*judgebitree(bt1->rchild,bt2->rchild));}1.设计两个有序单链表的合并排序算法。

图基本算法图的表示方法邻接矩阵邻接表

图基本算法图的表示方法邻接矩阵邻接表

图基本算法图的表⽰⽅法邻接矩阵邻接表 要表⽰⼀个图G=(V,E),有两种标准的表⽰⽅法,即邻接表和邻接矩阵。

这两种表⽰法既可⽤于有向图,也可⽤于⽆向图。

通常采⽤邻接表表⽰法,因为⽤这种⽅法表⽰稀疏图(图中边数远⼩于点个数)⽐较紧凑。

但当遇到稠密图(|E|接近于|V|^2)或必须很快判别两个给定顶点⼿否存在连接边时,通常采⽤邻接矩阵表⽰法,例如求最短路径算法中,就采⽤邻接矩阵表⽰。

图G=<V,E>的邻接表表⽰是由⼀个包含|V|个列表的数组Adj所组成,其中每个列表对应于V中的⼀个顶点。

对于每⼀个u∈V,邻接表Adj[u]包含所有满⾜条件(u,v)∈E的顶点v。

亦即,Adj[u]包含图G中所有和顶点u相邻的顶点。

每个邻接表中的顶点⼀般以任意顺序存储。

如果G是⼀个有向图,则所有邻接表的长度之和为|E|,这是因为⼀条形如(u,v)的边是通过让v出现在Adj[u]中来表⽰的。

如果G是⼀个⽆向图,则所有邻接表的长度之和为2|E|,因为如果(u,v)是⼀条⽆向边,那么u会出现在v的邻接表中,反之亦然。

邻接表需要的存储空间为O(V+E)。

邻接表稍作变动,即可⽤来表⽰加权图,即每条边都有着相应权值的图,权值通常由加权函数w:E→R给出。

例如,设G=<V,E>是⼀个加权函数为w的加权图。

对每⼀条边(u,v)∈E,权值w(u,v)和顶点v⼀起存储在u的邻接表中。

邻接表C++实现:1 #include <iostream>2 #include <cstdio>3using namespace std;45#define maxn 100 //最⼤顶点个数6int n, m; //顶点数,边数78struct arcnode //边结点9 {10int vertex; //与表头结点相邻的顶点编号11int weight = 0; //连接两顶点的边的权值12 arcnode * next; //指向下⼀相邻接点13 arcnode() {}14 arcnode(int v,int w):vertex(v),weight(w),next(NULL) {}15 arcnode(int v):vertex(v),next(NULL) {}16 };1718struct vernode //顶点结点,为每⼀条邻接表的表头结点19 {20int vex; //当前定点编号21 arcnode * firarc; //与该顶点相连的第⼀个顶点组成的边22 }Ver[maxn];2324void Init() //建⽴图的邻接表需要先初始化,建⽴顶点结点25 {26for(int i = 1; i <= n; i++)27 {28 Ver[i].vex = i;29 Ver[i].firarc = NULL;30 }31 }3233void Insert(int a, int b, int w) //尾插法,插⼊以a为起点,b为终点,权为w的边,效率不如头插,但是可以去重边34 {35 arcnode * q = new arcnode(b, w);36if(Ver[a].firarc == NULL)37 Ver[a].firarc = q;38else39 {40 arcnode * p = Ver[a].firarc;41if(p->vertex == b) //如果不要去重边,去掉这⼀段42 {43if(p->weight < w)44 p->weight = w;45return ;46 }47while(p->next != NULL)48 {49if(p->next->vertex == b) //如果不要去重边,去掉这⼀段50 {51if(p->next->weight < w);52 p->next->weight = w;53return ;54 }55 p = p->next;56 }57 p->next = q;58 }59 }60void Insert2(int a, int b, int w) //头插法,效率更⾼,但不能去重边61 {62 arcnode * q = new arcnode(b, w);63if(Ver[a].firarc == NULL)64 Ver[a].firarc = q;65else66 {67 arcnode * p = Ver[a].firarc;68 q->next = p;69 Ver[a].firarc = q;70 }71 }7273void Insert(int a, int b) //尾插法,插⼊以a为起点,b为终点,⽆权的边,效率不如头插,但是可以去重边74 {75 arcnode * q = new arcnode(b);76if(Ver[a].firarc == NULL)77 Ver[a].firarc = q;78else79 {80 arcnode * p = Ver[a].firarc;81if(p->vertex == b) return; //去重边,如果不要去重边,去掉这⼀句82while(p->next != NULL)83 {84if(p->next->vertex == b) //去重边,如果不要去重边,去掉这⼀句85return;86 p = p->next;87 }88 p->next = q;89 }90 }91void Insert2(int a, int b) //头插法,效率跟⾼,但不能去重边92 {93 arcnode * q = new arcnode(b);94if(Ver[a].firarc == NULL)95 Ver[a].firarc = q;96else97 {98 arcnode * p = Ver[a].firarc;99 q->next = p;100 Ver[a].firarc = q;101 }102 }103void Delete(int a, int b) //删除以a为起点,b为终点的边104 {105 arcnode * p = Ver[a].firarc;106if(p->vertex == b)107 {108 Ver[a].firarc = p->next;109 delete p;110return ;111 }112while(p->next != NULL)113if(p->next->vertex == b)114 {115 p->next = p->next->next;116 delete p->next;117return ;118 }119 }120121void Show() //打印图的邻接表(有权值)122 {123for(int i = 1; i <= n; i++)124 {125 cout << Ver[i].vex;126 arcnode * p = Ver[i].firarc;127while(p != NULL)128 {129 cout << "->(" << p->vertex << "," << p->weight << ")";130 p = p->next;131 }132 cout << "->NULL" << endl;133 }134 }135136void Show2() //打印图的邻接表(⽆权值)137 {138for(int i = 1; i <= n; i++)140 cout << Ver[i].vex;141 arcnode * p = Ver[i].firarc;142while(p != NULL)143 {144 cout << "->" << p->vertex;145 p = p->next;146 }147 cout << "->NULL" << endl;148 }149 }150int main()151 {152int a, b, w;153 cout << "Enter n and m:";154 cin >> n >> m;155 Init();156while(m--)157 {158 cin >> a >> b >> w; //输⼊起点、终点159 Insert(a, b, w); //插⼊操作160 Insert(b, a, w); //如果是⽆向图还需要反向插⼊161 }162 Show();163return0;164 }View Code 邻接表表⽰法也有潜在的不⾜之处,即如果要确定图中边(u,v)是否存在,只能在顶点u邻接表Adj[u]中搜索v,除此之外没有其他更快的办法。

邻接矩阵和关联矩阵

邻接矩阵和关联矩阵

邻接矩阵和关联矩阵一、概念解释邻接矩阵和关联矩阵是图论中常用的两种表示图的方式。

邻接矩阵是指用一个二维数组来表示图中各个节点之间的连接情况,其中数组的行和列分别代表节点,如果节点i和节点j之间有连边,则邻接矩阵中第i行第j列的元素为1,否则为0。

关联矩阵是指用一个二维数组来表示图中各个节点和边之间的联系,其中数组的行代表节点,列代表边,如果节点i与边j有关联,则关联矩阵中第i行第j列的元素为1或-1,分别表示该节点是边的起点或终点;如果该节点与该边没有关联,则为0。

二、邻接矩阵1.构建邻接矩阵要构建一个无向图G={V,E}的邻接矩阵A(V*V),可以按以下步骤进行:(1)初始化A为全0矩阵;(2)遍历E集合中每一条边(u,v),将A[u][v]和A[v][u]均设为1;(3)对角线上所有元素均设为0。

2.应用场景邻接矩阵适用于稠密图(即节点数较多,边数较多)的存储和计算,因为其空间复杂度为O(V^2),而且可以快速判断任意两个节点之间是否有连边。

3.优缺点邻接矩阵的优点包括:(1)易于理解和实现;(2)空间利用率高;(3)可以快速判断任意两个节点之间是否有连边。

邻接矩阵的缺点包括:(1)对于稀疏图(即节点数很多,但是边数很少),会浪费大量空间;(2)插入或删除节点时需要重新构建整个矩阵,时间复杂度为O(V^2);(3)如果图中存在重边或自环,则需要额外处理。

三、关联矩阵1.构建关联矩阵要构建一个无向图G={V,E}的关联矩阵B(V*E),可以按以下步骤进行:(1)初始化B为全0矩阵;(2)遍历E集合中每一条边(u,v),将B[u][e]和B[v][e]均设为1,其中e表示第e条边;(3)对于每个节点i,在B中找到与之相关的所有边,并将它们标记为-1,表示该节点是这些边的终点。

2.应用场景关联矩阵适用于稀疏图(即节点数很多,但是边数很少)的存储和计算,因为其空间复杂度为O(V*E),而且可以快速判断任意两个节点之间是否有连边。

图的连通性与矩阵表示

图的连通性与矩阵表示

若回路中除起点和终点 相同外,其余顶点互不 相同, 则称其为初级(基本) 回路。
有边重复出现的通路, 称为复杂通路。 有边重复出现的回路, 称为复杂回路。
初级通(回)路一定是 简单通(回)路。
3
如右图所示:
v1e 2 v 3 e 3 v 2就是v1到v 2
v2
v1的一条初级通路e4来自e3 e5v3
e2
4
定 理7.2.1: 在 一 个 图 中 , 若 从点 顶v i 到 顶 点 v j (v i v j ) 存在通路, 则 从v i 到v j 存 在 初 级 通 路 。
定 理7.2.2: 在 一 个 n阶 图 中 , (1) 任 何 初 级 通 路 的 长 度 不 均大 于 n 1。 ( 2) 任 何 初 级 回 路 的 长 度 不 均大 于 n。
1,
vi为ej的终点,
称M(D) = (mij)nm为D的关联矩阵。
v1
e2 v3 e3 e1 e4 v2 e5 v4
1 0 0 0 1 1 0 0 1 1 M ( D) 0 0 0 1 1 0 0 1 1 1
20
21
1
给定无向图G V , E ,设G中顶点和边的交替序列 为
v1e1v 2e2 ek v k 1,若满足:v i 和v i 1是ei的端点,
i 1,2, , k,则称为顶点v1到顶点v k 1的通路。
中边的数目k称为的长度。当v1 v k 1时,称为回路。
如右图所示:
e1
v4
当然也是一条简单通路
v1e2v3e5v5e7 v4e6v3e3v2
e6
v5
e7
也是v1到v2的一条简单通路,但却 不是初级通路

图部分习题1

图部分习题1

12.若无向图G(V,E)中含有7个顶点,则保证图G在任何情况下都是
连通的,则需要的边数最少是___.
A. 6 B. 15 C. 16
D. 21
解: 对于具有n个顶点的无向图,当其中n-1顶点构成一个完 全图时,再加上任意一条边必构成一个连通图,所以最少边数 =(n-1)(n-2)/2+1=16.答案为C.
1 所有顶点的度之和为偶数;
2 边数大于顶点个数减1;
3 至少有一个顶点的度为1;
A. 只有1 B. 只有2.
C. 1和2.
D. 1和3
解: 在无向图中,一条边在度之和中计为2,所以度之和为边数的 2倍,1正确.无相连通图边数最少时为树图的情况,此时边数为顶 点个数减1,2错误.一个顶点数为3,边数为3的无相连通图中所有 顶点度为2,3错误. 答案为A.
2. 对于一个非连通无向图G,采用深度优先遍历算法访问所有 顶点,调用DFS()的次数正好等于____。 A、顶点个数 B、边的数目 C、连通分量的数目 D、不确定 解:正确答案C。
ቤተ መጻሕፍቲ ባይዱ
3. 对于采用邻接表存储的图,其深度优先遍历算法类似于二叉 树的____算法。 A、先序遍历 B、中序遍历 C、后序遍历 D、按层遍历 解:正确答案A。
5.4.2 1.一个无向连通图的生成树是含有该连通图的全部顶点的__. A.极小连通子图 B. 极小子图 C.极大连通子图 D.极大子图
解:生成图是含有全部顶点的极小连通子图. 答案为A.
解:连通分量是无向图的极大连通子图,其中极大的含义是将依附 于连通分量中顶点的所有边都加上,所以,连通分量中可能存在 回路,这样就不是生成树了,本题答案为B.
A. 0
B. 1
C. n-1

带权无向图

带权无向图

带权无向图(用邻接矩阵表示)#include <>#include<>#define int_max 10000#define inf 9999#define max 20dj=int_max;[i][j].info=NULL;}printf("输入一条边依附的顶点和权:\n");for(int k=0;k!=;++k){scanf("%c%c%d",&v1,&v2,&w); dj=w;[j][i].adj=w;}return ;}typedef struct ArcNode 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;}}}}=;=;printf("图G的邻接表创建成功!\n"); return 1;}typedef struct{int adjvex;int lowcost;}closedge;int prim(int g[][max],int n) \n");printf("1、使用prim算法求最小生成树……………\n"); printf("2、退出系统…………………………………\n\n"); }void main(){ALGraph G1;MGraph_L G;int i,d,g[20][20];char y='y';int k;while(y=='y'){list();printf("请选择菜单:\n");scanf("%d",&k);switch(k){case 0:d=createMGraph_L(G);CreateUDG(G1,G);break;case 1:for(i=0;i!=;++i)for(int j=0;j!=;++j)g[i+1][j+1]=[i][j].adj;printf("prim:\n");prim(g,d);break;case 2:break;//exit(1);}printf("\n是否继续操作y/n:");scanf("%c",&y);}}。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
相关文档
最新文档