图论基础--存储边的4种方式

邻接矩阵

作为最简单的存边方式,那当然是要掌握啦。基本原理就是利用f[n][n]来存边。f[i][j]的值若为真,则表明I与j间存在边,否则没有边。既可以存单向边也可以存双向边。同时f也可以存储边的权值。另外根据矩阵乘法的定义,f*f可以表示经过一个中间点后的链接状态。缺点也很明显啦,所占内存过大(尤其是存双向边时),遍历寻找下一个点时效率低等。总体来说数据不是太刁钻时就可以用。

相关复杂度

时间o(n ^ 2) , 空间o(n ^ 2)。

代码实现

#include
using namespace std;
int f[505][505];
int n,m;
void src(int u)//遍历 
{
 for(int i=1;i<=n;i++)
 {
  if(f[u][i])
  {
   src(i);
  }
 }
}
int main()
{
 scanf("%d%d",&n,&m);
 for(int i=0;i<m;i++)//插入,删除再赋值为0就好了 
 {
  int x,y,z;
  scanf("%d%d%d",&x,&y,&z);//单向边,双向边记得反过来再来一遍 
  f[x][y]=z;
 }
 src(1);
 return 0;
}

邻接链表

主要用来存稀疏图。基本原理是利用多个单向链表来存边。

相关复杂度

时间o(n+m),空间o(n+m)

代码

#include
#include
#include
using namespace std;
int n,m;
int tol;
int hd[50],nxt[500],num[500],w[500];
void add(int u,int v,int w1)
{
 if(hd[u])
 {
  int now=hd[u];
  while(nxt[now]) now=nxt[now];
  tol++;
  nxt[now]=tol;
  num[tol]=v;
  w[tol]=w1;
  return;
 }
 else
 {
  tol++;
  hd[u]=tol;
  tol++;
  nxt[hd[u]]=tol;
  num[tol]=v;
  w[tol]=w1;
 }
}
void del(int x,int y)
{
 int pr,now=hd[x];
 while(num[now]!=y) pr=now,now=nxt[now];
 nxt[pr]=nxt[now];
}
int main()
{
 scanf("%d%d",&n,&m);
 for(int i=1;i<=m;i++)
 {
  int x,y,z;
  scanf("%d%d%d",&x,&y,&z);
  add(x,y,z);//增加由x向y的边 
 }
 int x,y;
 scanf("%d%d",&x,&y);
 del(x,y);//删除x到y的边 
 for(int i=1;i<=n;i++)
 {
  printf("%d\n",i);
  int now=nxt[hd[i]];
  while(num[now])
  {
   printf("%d %d\n",num[now],w[now]);
   now=nxt[now];
  }
 }
 return 0;
 } 

链式前向星

这个也比较常用。主要是利用结构体edge来存边,但在使用前需要预处理数据以加快使用。

代码

#include
#include
#include
using namespace std;
int n,m,tol;
int hd[55];
struct edge{
 int to;//另一个点
 int w;//权
 int nxt;//下一个同起点边的下标 
}e[5005];
void add(int u,int v,int k)
{
 tol++;
 e[tol].nxt=hd[u];
 e[tol].to=v;
 e[tol].w=k;
 hd[u]=tol;
}
void del(int u,int v)
{
 int pr=0;
 for(int i=hd[u];i;i=e[i].nxt)
 {
  if(e[i].to==v)
  {
   if(i==hd[u]) hd[u]=e[i].nxt;
   else e[pr].nxt=e[i].nxt;
   return;
  }
  pr=i;
 }
}
int main()
{
 scanf("%d%d",&n,&m);
 for(int i=1;i<=m;i++)
 {
  int x,y,z;
  scanf("%d%d%d",&x,&y,&z);
  add(x,y,z);//增加x到y的边 
 }
 int x,y; 
 scanf("%d%d",&x,&y);
 del(x,y);//删除x到y的边; 
 for(int i=1;i<=n;i++)
 {
  printf("%d\n",i);
  for(int j=hd[i];j;j=e[j].nxt)
  {
   printf("%d %d\n",e[j].to,e[j].w);
  }
 }
 return 0;
}

vector邻接表

简单来说就是邻接矩阵的优化版本。

代码

#include
#include
#include
#include
using namespace std;
vector<int>map[55];
int main()
{
 int n,m;
 scanf("%d%d",&n,&m);
 for(int i=1;i<=m;i++)
 {
  int x,y;
  scanf("%d%d",&x,&y);
  map[x].push_back(y);
 }
 int x,y;
 scanf("%d%d",&x,&y);
 for(int i=0;i<map[x].size();i++)
 {
  if(map[x][i]==y)
  {
   map[x].erase(map[x].begin()+i);
   break;
  }
 }
 for(int i=1;i<=n;i++)
 {
  int len=map[i].size();
  printf("%d\n",i);
  for(int j=0;j<len;j++)
  {
   printf("%d ",map[i][j]);
  }
  cout<<endl;
 }
 return 0;
}

你可能感兴趣的:(图论)