图
构造图(存储结构)
利用邻接矩阵
- 邻接矩阵——优点?
-
- 直观、简单、好理解
-
- 方便检查任意一对顶点间是否存在边
-
- 方便找任一顶点的所有“邻接点”(有边直接相连的顶点)
-
- 方便计算任一顶点的“度”
- 缺点:
-
- 不便于增加和删除顶点
-
- 浪费空间
-
- 浪费时间(需要统计有多少边)
代码
#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;
}