数组实现邻接链表

zhyjc6于2020-09-11发布 约1703字·约3分钟 本文总阅读量

前言

我们在之前的一篇文章中已经提到了图的表示:图的表示?关联矩阵、邻接矩阵、邻接链表。其中提到了一种方法,叫做邻接链表。

邻接链表,顾名思义,就是将所有与某个结点相邻的结点收集起来,一一添加在一条单链表上面。这种方法相对于邻接矩阵而言大大节约了内存空间。

但有时候我们不太喜欢使用链表来存储,因为这样显得不太方便。所以,我们可以尝试使用数组来实现邻接链表。那么如何实现呢?

如何实现

我们假设给出的图是 a,b,w,表示结点a与b相连,边ab的权值为w。那么我们可以尝试给每一条边进行编号,比如第一条边编号为1(或者为0),后面的边依次累加。

定义三个数组即可:

如何添加一条边

首先我们要为每一条边进行编号,可以使用全局变量来实现,每添加一条边就将其加一。然后再想如何添加,比如我们需要添加的一条边是 a,b,w,边的编号为idx,那么:

如何遍历

对于给出的一个结点a,我们可以通过for (int edge = h[a]; edge != -1; edge = ne[edge]) child = e[edge] 来进行遍历与其相邻的每一个结点。如果给出的图是连通图,那么我们就可以通过给出的任意一个结点访问到图中的所有结点,当然这个过程需要我们自己控制重复访问的问题。这样,就达到了用数组实现邻接链表的效果。

测试代码

#include <iostream>
#include <vector>

using namespace std;

const int N = 1000;
int e[N];   //edge,e[i]表示标号为i的边的指向的结点
int ne[N];  //next_edge,ne[i]表示标号为i的边的下一条边的编号
int h[N];   //head,h[i]表示结点i的最后添加的一条边的编号(相当于邻接链表头结点)
int idx;    //index,边的标号,一般可以从0或1开始

//添加一条从a到b的边
void add(int a, int b) {
	e[idx] = b;  //边idx指向结点b
	ne[idx] = h[a];  //边idx的下一条边为之前最后添加的边(相当于在单链表头部插入新结点)
	h[a] = idx++;  //更新当前边为最后添加的边
}

void init() {
	for (int i = 0; i < N; ++i) {
		e[i] = ne[i] = h[i] = -1;
	}
	idx = 0; //边的编号可以从0或者1开始
}

int main() {
	int n, a, b;
	while (1) {
		init();
		cout << "初始化完成,请输入边的数量:" << endl;
		cin >> n;
		cout << "请输入" << n << "条边,以空格或回车分隔" << endl;
		while (n--) {
			cin >> a >> b;
			add(a, b);
		}
		for (int i = 0; i < N; ++i) {
			if (h[i] == -1) continue;
			cout << "node " << i << ": ";
			for (int j = h[i]; j != -1; j = ne[j]) {  //j为结点i下的每一条边
				cout << e[j] << " ";
			}
			cout << endl;
		}
		cout << endl;
	}
}