图
构造图(存储结构)
利用邻接矩阵
- 邻接矩阵——优点?
-
- 直观、简单、好理解
-
- 方便检查任意一对顶点间是否存在边
-
- 方便找任一顶点的所有“邻接点”(有边直接相连的顶点)
-
- 方便计算任一顶点的“度”
- 缺点:
-
- 不便于增加和删除顶点
-
- 浪费空间
-
- 浪费时间(需要统计有多少边)
代码
#include<stdio.h> #include<algorithm> #include<cmath> #include<iostream> using namespace std; #define MVNum 100 #define MaxInt 32767//极大值 typedef struct//最大顶点数 { int vexs[MVNum];//顶点表 int arcs[MVNum][MVNum];//邻接矩阵 int vexnum,arcnum;//图当前点数和边数 }AMGraph; int LocateVex(AMGraph G,int u) { int i; for(i=0;i<G.vexnum;i++) { if(u==G.vexs[i]) return i; } return -1; } //构造无向网 /* 无向图: 1.初始化邻接矩阵时,w均为0; 2.构造邻接矩阵时,w为1; ///或直接去掉权值w 有向网: (因为邻接矩阵为非对称矩阵,) 仅向G.arc[i][j]赋值,不向G.arcs[j][i]赋值即可 有向图: .......... */ //初始化邻接矩阵 void Created(AMGraph &G) { cin>>G.vexnum>>G.arcnum; int i;int j; for(i=0;i<G.vexnum;i++) { cin>>G.vexs[i]; } for(i=0;i<G.vexnum;i++) { for(j=0;j<G.arcnum;j++) { G.arcs[i][j]=MaxInt; } } int v1,v2,w; int k; for(k=0;k<G.arcnum;k++)//构造邻接矩阵 { cin>>v1>>v2>>w;//输入一条边的两顶点和权值 i=LocateVex(G,v1); j=LocateVex(G,v2); G.arcs[j][i]=G.arcs[i][j]=w; } } int main() { AMGraph G; Created(G); return 0; }
利用邻接表
特点
- 对于无向图
-
- 邻接表不唯一
-
- 若无向图有n个顶点,e条边,则邻接表需要n个头结点,2e个表节点.
-
- 适宜稀疏图
- 对于有向图:
-
- 找出度易:顶点v(i)的出度为第i个单链表中的结点个数。
-
- 找出度难:需要全部遍历,顶点V的入度为整个单链表中邻接点域值是i-1的结点个数
-
- 可以使用逆邻接表,则找出入度易,找出度难
代码
#include<stdio.h> #include<algorithm> #include<cmath> #include<iostream> using namespace std; #define MVNum 100 //容量 #define MaxInt 32767//极大值 //弧(边)的结点定义 typedef struct ArcNode { int adjvex;//该边所指向的顶点的位置 struct ArcNode *nextarc;//指向下一条边的指针 // Otherlnfo info;//和边相关的其他信息 } ArcNode; //顶点结构体 typedef struct VNode { int data;//顶点信息 ArcNode *firstarc;//指向第一条边的指针 } VNode,AdjList[MVNum];//AdjList表示邻接表类型 /* 说明:AdjList v 等价于 VNode v[MVNum]; */ //定义图 typedef struct { AdjList vertices;//vertices--vertex的复数 int vexnum,arcnum;//图的当前顶点数和弧数 } ALGraph; int LocateVex(ALGraph G,int k) { int i; for(i=0;i<G.arcnum;i++) { if(G.vertices[i].data == k) return i; } return -1; } //采用邻接法表示法,创建无向网G void CreateUDG (ALGraph &G) { cin>>G.vexnum>>G.arcnum;//输入总顶点,总边数 int i,j; for(i=0;i<G.vexnum ;i++)//建立表头节点表 { cin>>G.vertices[i].data;//顶点值 G.vertices[i].firstarc=NULL;//初始化指向的边 } int v1,v2,k; for(k=0;k<G.arcnum ;k++)//输入边,构造邻接表 { cin>>v1>>v2;//输入边,依附的两个顶点 i=LocateVex(G,v1);//查找到顶点1位置 j=LocateVex(G,v2);//查找到顶点2位置 ArcNode *p1 = new ArcNode;//生成新的边结点 p1->adjvex = j;//邻接序号为j; p1 -> nextarc = G.vertices[i].firstarc; G.vertices[i].firstarc=p1;//头插进顶点d边表头部 ArcNode *p2 = new ArcNode; p1->adjvex =i; p1 -> nextarc = G.vertices[j].firstarc; G.vertices[j].firstarc=p1; } } int main() { ALGraph G; return 0; }
区别邻接矩阵和邻接表
用途
邻接矩阵用于稠密图,邻接表用于稀疏图
联系
- 联系:邻接表中每个链表对应于邻接矩阵中的一行,链表中结点个数等于一行中非零元素的个数。
区别 - 对于任一确定的无向图,邻接矩阵是唯一的(行列号与顶点编号一
致), -
- 但邻接表不唯一(链接次序与顶点编号无关)。
- 邻接矩阵的空间复杂度为O(n的2次幂),
-
- 而邻接表的空间复杂度为o(n+e)。
十字链表和临接多重表
十字链表(用于有向图)
解决:邻接表求结点的度困难
方法:
- 顶点结点,增加一个指向 入度的指针
- 边结点,增加 入度顶点信息,
临接多重表(用于无向图)
解决:邻接表的而
实战
存储
邻接矩阵构建
//用c语言写,c++会超时
#include<stdio.h> #include<iostream> #include <string.h> #include <stdbool.h> using namespace std; bool a[5005][5005]; int main() { int n,m, i, u,v, x,y, q; while(scanf("%d %d",&n,&m)!=EOF) { memset(a,0,sizeof(a)); for(i=0; i<m; i++) { cin>>u>>v; a[u][v]=1; } cin>>q; for(i=0; i<q; i++) { cin>>x>>y; if(a[x][y]==1) cout<<"Yes"<<endl; else cout<<"No"<<endl; } } return 0; }
邻接表存储
//用c语言写,c++会超时
#include<stdio.h> #include<iostream> #include <string.h> #include <stdbool.h> using namespace std; struct node { int data; struct node *next; }; int main() { int n,m; while(cin>>n>>m) { int i,u,v; struct node *G[500001],*Q; for(i=0;i<n;i++) { G[i]=(struct node*)malloc(sizeof(struct node)); G[i]->next=NULL; G[i]->data=-1; } for(i=0;i<m;i++) { cin>>u>>v; Q=(struct node*)malloc(sizeof(struct node)); Q->data=v; Q->next=G[u]->next; G[u]->next=Q; } int p; cin>>p; int a,b; for(i=0;i<p;i++) { cin>>a>>b; Q=G[a]; while(Q!=NULL) { if(Q->data==b) { cout<<"Yes"<<endl; break; } Q=Q->next; } if(Q==NULL) { cout <<"No"<<endl; } } } return 0; } ### [图的基本存储的基本方式三](https://acm.sdut.edu.cn/onlinejudge3/problems/3118 "图的基本存储的基本方式三")
#include<stdio.h> #include<iostream> #include <string.h> #include <stdbool.h> using namespace std; typedef struct { int a=0; int b=0; int c=0; }TU; void q_sort(TU a[],int l,int r)//快速排序 { TU key=a[l]; int i=l; int j=r; if(l>=r) return; while(i<j) {//权值w小的在前; //权值相等时出发点u小的在前; //权值和出发点相等时到达点v小的在前 while(i<j &&(key.c<a[j].c ||(key.c==a[j].c&&key.a<a[j].a) ||(key.c==a[j].c&&key.a==a[j].a&&key.b<a[j].b))) j--; a[i]=a[j]; while(i<j&&(key.c>a[i].c ||(key.c==a[i].c&&key.a>a[i].a) ||(key.c==a[i].c&&key.a==a[i].a&&key.b>a[i].b))) i++; a[j]=a[i]; } a[i]=key; q_sort(a,l,i-1); q_sort(a,i+1,r); } int main() { int n,m; while(cin>>n>>m) { TU G[m]; int i; for(i=0;i<m;i++) { cin>>G[i].a>>G[i].b>>G[i].c; } //sort(G.c,G.c+m); q_sort(G,0,m-1); int q; cin>>q; int k; for(i=0;i<q;i++) { cin>>k; cout<<G[k].a<<" "<<G[k].b<<endl; } } return 0; }
用邻接表
#include <stdio.h> #include <stdlib.h> #include <string.h> struct node { int data; struct node *next; }*a[5010]; void add(int i, int j) { struct node *q; q = (struct node *)malloc(sizeof(struct node)); q->data = j; q->next = NULL; if(a[i] == NULL){ a[i] = q; }else { q->next = a[i]->next; a[i]->next = q; } } int main() { int n; while(~scanf("%d", &n)){ int i, j; int x; int u, v; struct node *p; for(i = 0;i < n;i++){ a[i] = NULL; } for(i = 0;i < n;i++){ for(j = 0;j < n;j++){ scanf("%d", &x); if(x == 1){ add(i,j); } } } int q; scanf("%d", &q); int flag; while(q--){ scanf("%d %d", &u, &v); flag = 0; p = a[u]; while(p){ if(p->data == v){ flag = 1; break; } p = p->next; } if(flag){ printf("Yes\n"); }else { printf("No\n"); } } } return 0; }
本文作者:kingwzun
本文链接:https://www.cnblogs.com/kingwz/p/15158651.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步