图的存储结构---(*链式前向星*)


(写出来仅供随时参考)


邻接矩阵


代码引自my_Dijkstra

typedef struct ArcCell {
    int weight; // 邻接矩阵的元素即为图的边的权值
}ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];

typedef struct {
    int vexs[MAX_VERTEX_NUM]; // 存放顶点的数组
    AdjMatrix arcs; // 邻接矩阵
    int vexnum,arcnum; //图的当前顶点数和弧数
}MGraph;
  • 优点
    • 实现简单直观
    • 可以直接查询两点之间是否连通
  • 缺点
    • 遍历效率低
    • 不能存储重边/平行边
    • 初始化效率低
    • 大图的空间开销大

前向星


int head[maxn]; // 存储起点为Vi的第一条边的位置

struct NODE {
    int from;
    int to;
    int w; // weight
};
NODE edge[maxm];

// 比较函数
// 将所有边的信息读入,按照边的起点排序,
// 若起点相同,对于相同起点的边按终点排序,
// 如果仍有相同,按权值排序
bool cmp(NODE a, NODE b) {
    if(a.from==b.from && a.to==b.to) return a.w<b.w;
    if(a.from==b.from) return a.to<b.to;
    return a.from<b.from;
}

// 读入数据
cin>>n>>m;
for(i=0;i<m;i++) cin>>edge[i].from>>edge[i].to>>edge[i].w;
sort(edge,edge+m,cmp);
memset(head,-1,sizeof(head));
head[edge[0].from]=0;
for(i=1;i<m;i++)
    if(edge[i].from != edge[i-1].from) head[edge[i].from]=i;

// 遍历
for(i=1;i<=n;i++) {
    for(k=head[i];edge[k].from==i && k<m;k++) {
        cout<<edge[k].from<<" "<<edge[k].to<<" "<<edge[k].w;
        cout<<endl;
    }
}


  • 优点

    • 可应对点很多的情况
    • 可存储重边
  • 缺点

    • 排序会浪费时间
    • 无法直接判断两点之间是否连通



邻接表(三种实现)


动态建表


代码引自my_Prim

// 表边结点
typedef struct ArcNode {
    int weight;
    int adjvex;
    struct ArcNode *nextarc;
}ArcNode;
// 表头结点
typedef struct VNode {
    int data;
    ArcNode *firstarc;
}VNode,AdjList[MAX_VERTEX_NUM];
// 图
typedef struct {
    int vexnum,arcnum;
    AdjList vertices;
}ALGraph;

  • 缺点
    • 内存释放是个问题



STL/vector模拟链表实现

struct EdgeNode {
    int to;
    int w;
};
vector<EdgeNode> map[maxn];

EdgeNode e;
cin>>i>>j>>w;
e.to=j; e.w=w;
map[i].push_back(e);

// 遍历
for(i=1;i<=n;i++) {
    for(vector<EdgeNode>::iterator k=map[i].begin();k!=map[i].end;k++) {
        NODE t=*k;
        cout<<i<<' '<<t.to<<' '<<t.w<<endl;
    }
}

  • 优点
    • 代码量少
    • 不易犯错
    • 内存的申请与释放不需要自己处理


静态建表(链式前向星)


// head数组存储描述点Vi边信息的链的起点在Edges数组的位置
int head[n];
struct EdgeNode {
    int to;
    int w;
    int next;
};
EdgeNode Edges[m];
// 构造链式前向星就是将新加入的结点链在对应链的最开始
// 并修改head数组的对应位置的值

// 信息存储
cin>>i>>j>>w;
Edges[k].to=j;
Edges[k].w=w;
Edges[k].next=head[i]; // 将当前新加入的边的next值
                        // 设为上条边在Edges中的位置
head[i]=k; // 将当前新加入的边链在之前的边上
// 上两行的操作就和链表中加入一个新结点的操作的意思一样

// 遍历
for(i=1;i<=n;i++) {
    for(k=head[i];k!=-1;k=edge[k].next) {
        cout<<i<<" "<<edge[k].to<<" "<<edge[k].w<<endl;
    }
}
No.12345678
head10011611279


No.123456789101112
to813213457627
w2912114221725979194
next000000023458



链式前向星除了不能直接用起点终点判断是否连通以外,几乎是完美的




References

  1. 《ACM-ICPC程序设计系列 图论及应用》
  2. my___github
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值