邻接表
对于一个无向图,有邻接矩阵和邻接表等存储方式,而其中邻接表的实现方式无疑让人很纠结。
邻接表的优点在于,对于节点为n的稀疏无向图,邻接矩阵需要耗费的空间为n2,而邻接表仅需耗费2n的空间。使用邻接表存储图,无疑大大降低了存储所必须的空间。
这里主要讲解邻接表的数组实现。
对于邻接表,一般包含两个部分:第一部分用于存储无向边的信息,第二部分拥有存储节点的起始边编号,如下:
在这里我们使用结构体数组来存储无向边的信息,代码如下:
struct LINE{
int p; //被连接的节点号
int next; //边表中下一条边的ID
};
LINE l[MAX * 2]; //无向图,边的数量*2
使用一个一维数组来存储节点的起始边编号,如下:
int h[MAX];
举这样一个例子,对于以下无向图:
起始点 | 1 | 2 | 3 | 4 | 2 |
结束点 | 2 | 4 | 2 | 4 | 5 |
我们可以将其存储为如下形式:
对于一维数组h部分有:
h[1] | h[2] | h[3] | h[4] | h[5] |
1 | 5 | 3 | 4 | 0 |
对于结构体数组l部分有:
l[1] | l[2] | l[3] | l[4] | l[5] | |||||
p | next | p | next | p | next | p | next | p | next |
2 | 0 | 4 | 0 | 2 | 0 | 3 | 0 | 5 | 2 |
值得注意的是,对于每一个新加入链表的边节点,我们都将其插入到链表头部,而不是将其插入到链表尾部。
具体的存储过程实现代码如下:
void add(int n) //无向图中节点个数
{
int a, b;
for(int i = 1; i <= n; i++)
{
cin>>a>>b;
l[i].p = b;
l[i].next = h[a];
h[a] = i;
}
}
当我们需要对第i号节点进行遍历时,只需如下操作:
void search(int i) //需要遍历的节点编号
{
int k = h[i];
while(k != 0)
{
cout<<l[k].p<<' ';
k = l[k].next;
}
}
--------------------------------------------------------------------------------------------------------------------------------------------
2018.8.1补充:
当我们需要对整个无向图进行遍历时,也可以如下操作:
void search(int f, int i) { int k = h[i]; int p; while(k) { p = l[k].p; if(p != f) { search(i, p); } k = l[k].next; } }
圆满完成。