您的位置:首页 > 其它

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

2017-04-10 23:56 288 查看
(写出来仅供随时参考)

邻接矩阵

代码引自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<
4000
/span>,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
;
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

《ACM-ICPC程序设计系列 图论及应用》

my___github
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: