邻接多重表(Adjacency Multilist)是无向图的另一种链式存储结构
图的邻接表(Adjacency List)表示
有向图的十字链表(Orthogonal List)表示
我们在使用邻接表来存储无向图的时候,虽然很方便,很容易求得顶点和边的各种信息,但是邻接表里无向图的每一个边都是用两个边结点来表示(如图)
这样子在对边的操作会比较麻烦,比如在图的搜索中,我们要对已经搜索过的边作个记号,就比较麻烦了!因为一条边会对应这2个边结点,在这一个边结点作标记之后还要寻找另一个边结点,时间效率不高。
邻接多重表则对这些问题作出改进,每一条边都只对应一个边结点,具体实现方法和十字链表相似。
/*
边结点
*/
struct Edge{
bool mark; //访问标记
int ivex,jvex; //这条边依附的两个顶点的位置
Edge* inext,*jnext; //依附顶点ivex,jvex的下一条边
};
代码
/*
邻接多重表
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define maxn 1024 //最大顶点数
int n,m;//顶点个数,边的个数
/*
边结点
*/
struct Edge{
bool mark; //访问标记
int ivex,jvex; //这条边依附的两个顶点的位置
Edge* inext,*jnext; //依附顶点ivex,jvex的下一条边
};
/*
顶点
*/
struct VNode{
Edge* firstedge; //第一条依附于该顶点的边
}vlist[maxn];
/*
增加一条依附于顶点v1和v2的边
*/
void link(int v1,int v2){
Edge* e = new Edge;
e->ivex = v1;
e->jvex = v2;
//下面是链表插入常规操作
e->inext = vlist[v1].firstedge;
vlist[v1].firstedge = e;
e->jnext = vlist[v2].firstedge;
vlist[v2].firstedge = e;
}
/*
初始化
*/
void init(){
n = 5;
m = 6;
//初始化vlist
for(int i = 1;i<=n;++i){
vlist[i].firstedge = NULL;
}
//以下m行建图
link(1,2);
link(1,4);
link(2,3);
link(2,5);
link(3,4);
link(3,5);
}
/*
打印邻接表
*/
void print(){
Edge* e = NULL;
for(int i = 1;i<=n;++i){
cout << "v" << i << ": ";
e = vlist[i].firstedge;
while(e){
if(e->ivex == i){
//该边的ivex是顶点i
cout << e->jvex << " -> ";
e = e->inext;
}else{
//该边的jvex是顶点i
cout << e->ivex << " -> ";
e = e->jnext;
}
}
cout << "^" << endl;
}
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
init();
print();
return 0;
}
运行结果
表示的无向图如下:
思考
邻接表的边结点:
//边节点
struct ArcNode{
int adjvex; //改边指向的顶点的位置
ArcNode* next; //指向的下一个顶点
// int lowcost; //权值
};
邻接多重表的边结点:
/*
边结点
*/
struct Edge{
bool mark; //访问标记
int ivex,jvex; //这条边依附的两个顶点的位置
Edge* inext,*jnext; //依附顶点ivex,jvex的下一条边
};
邻接表是每一条边都有2个边结点分别附在2个链表,而邻接多重表是每一条边都只有1个边结点,都附在两个链表上,再看看两种方法的结构体的成员数目,可见,在邻接多重表中,除了在边结点添加一个标志域外,所占的空间和邻接表是一样的!