欢迎来到endl的博客hhh☀☾☽♡♥

浏览器标题切换
把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

图的存储结构

1.二维数组邻接矩阵存储

定义int G[101][101]; G[i][j]的值,表示从点i到点j的边的权值,定义如下:

2.二维数组邻接矩阵存储的优化 (多用于稠密图

int g[101][101],num[101];   //num[i]记录与顶点i相连的边数,增强顶点的联系
double w[101][101];
cin >> e;
for (k = 1; k <= e; k++)
{
cin >> i >> j >> v;             //读入两个顶点序号及权值
w[i][j]=w[j][i]=v;
g[i][++num[i]] = j;             //对于不带权的图g[i][j]=1
g[j][++num[j]] = i;             //无向图的对称性, 有向图则不要!
} 

查询:O(e)//边数
for(int i=1;i<=n;i++)
for(int j=1;j<=num[i];j++)
{
  直接调用w[i][g[i][j]]……
}

3. STL邻接矩阵存储的优化

(关于vector的用法,请见☟

Vector(动态数组)怎么用咧↓↓↓ - endl\n - 博客园  https://www.cnblogs.com/ljy-endl/p/11271899.html)

vector<int>g[101];
double w[101][101];
cin >> e;
for (k = 1; k <= e; k++)
{
cin >> i >> j >> v;             //读入两个顶点序号及权值
w[i][j]=w[j][i]=v;
g[i].push_back(j);//对于不带权的图g[i][j]=1
g[j].push_back(i);//无向图的对称性, 有向图则不要!
} 
查询:O(e)//边数
for(int i=1;i<=n;i++)
for(int j=0;j<g[i].size();j++)
{
  直接调用w[i][g[i][j]]……
}

4.数组模拟邻接表存储(!!!)(多用于稀疏图

例:将下图用数组模拟邻接表存储

因为此图是无向图,所以还可以由输入得到:

然后再将上述数据整理一下,得到下表:

i为第几条边,from指起点,to指终点,w指长度

(注意不同颜色的数字和箭头)

 将上表按照 从第几个顶点开始 的方式用下图存储

(数据处理完之后:head[第i个顶点]=i连接的最后一条边,然后又通过这一条边的nxt查询连接i顶点的下一条边,直到nxt=0为止

(注意:是倒序存储,这样可以避免正序查找时重复遍历数组)

将上图所示的过程用代码写粗来就是下面的红色字体:

#include <iostream>
using namespace std;
const int maxn=1001,maxm=100001;
struct Edge
{
    int next;                               //下一条边的编号 
    int to;                                 //这条边到达的点 
    int dis;                                //这条边的长度 
}edge[maxm];              //也可以用to[maxm],dis[maxm],nxt[maxm]三个数组替代

int head[maxn],num_edge,n,m,u,v,d;//head[]表头,num_edge当前加入第几条边

void add_edge(int from,int to,int dis)      //加入一条从from到to距离为dis的单向边 
{
    edge[++num_edge].next=head[from];
    edge[num_edge].to=to;
    edge[num_edge].dis=dis;
    head[from]=num_edge;
}
int main()
{
    num_edge=0;
    scanf("%d %d",&n,&m);                    //读入点数和边数
    for(int i=1;i<=m;i++)
    {
          scanf("%d %d %d",&u,&v,&d);   //u、v之间有一条长度为d的边 
          add_edge(u,v,d);
                   add_edge(v,u,d);                          //无向边多加一条反向的
    }
         for(int j=1;j<=n;j++)
    for(int i=head[j];i!=0;i=edge[i].next)   //遍历从点j开始的所有边 
    {
           //...
    }

    //...

    return 0;
}

 

posted @ 2019-07-30 19:18  endl\n  阅读(429)  评论(0编辑  收藏  举报