您的位置:首页 > 其它

图的基本知识及实现_邻接矩阵_邻接表

2016-05-30 14:17 357 查看
对于有 nn 个顶点的图 G = (V, E)来说,我们可以用一个 n * n的矩阵 AA来表示 G中各顶点的相邻关系,如果 v_{i}和 v_{j}之间存在边(或弧),则

A[i][j] = 1,

否则 A[i][j] = 0。

下图为有向图 G_{1}G1

​​ 以及对应的邻接矩阵。





下图为无向图 G_{2}G2

​​ 以及对应的邻接矩阵。





图的邻接矩阵是唯一的,矩阵的大小只与顶点个数 NN 有关,是一个 N * NN∗N 的矩阵。前面我们已经介绍过,在无向图里,如果顶点 v_{i}vi

v_{j}v​j之间有边,则可认为顶点 v_{i}v​i到 v_{j}v​j有边,同时顶点 v_{j}v​j到 v_{i}v​i 也有边。对应到邻接矩阵里,

则有

A[i][j]=A[j][i]=1。

因此我们可以发现,无向图的邻接矩阵是一个对称矩阵。

在邻接矩阵上,我们可以直观的看出两个顶点之间是否有边(或弧),并能容易求出每个顶点的度,入度和出度。

这里我们以图 G_{1}G​1为例,演示下如何利用邻接矩阵计算顶点的入度和出度。顶点的出度,即为邻接矩阵上点对应行上所有值的总和,比如顶点 1 对应的出度即为

0+1+1+1=3;而每个点的入度即为点对应列上所有值的总和,比如顶点 3 对应的入度即为

1+0+0+1=2。





我们再来学习邻接表

邻接表是图的一种顺序存储与链式存储相结合的存储方法。我们给图 GG 中的每个顶点建立一个单链表,第 ii 个单链表中的结点表示依附于顶点 v_{i}​​ 的边(对于有向图是以 v_{i}为起点的弧)。所有单链表的表头结点都存储在一个一维数组中,以便于顶点的访问。下图为图 G_{1}对应的邻接表。





在无向图的邻接表中,顶点 v_{i}的度为第 i个单链表中的结点数;而在有向图中,第 ii 个单链表中的结点数表示的是顶点 v_{i}v

​i的出度,如果要求入度,则要遍历整个邻接表。另外,在邻接表中,我们很容易就能知道某一顶点和哪些顶点相连接。

学习完两种存储结构,可能你会有这样的疑问:那我们什么时候用邻接矩阵,什么时候用邻接表呢?

我们可以看到,邻接矩阵存储结构最大的优点就是简单直观,易于理解和实现。其适用范围广泛,有向图、无向图、混合图、带权图等都可以直接用邻接矩阵表示。另外,对于很多操作,比如获取顶点度数,判断某两点之间是否有连边等,都可以在常数时间内完成。

然而,它的缺点也是显而易见的:从以上的例子我们可以看出,对于一个有 n 个顶点的图,邻接矩阵总是需要n​2的存储空间。当边数很少的时候,就会造成空间的浪费。

因此,具体使用哪一种存储方式,要根据图的特点来决定:如果是稀疏图,我们一般用邻接表来存储,这样可以节省空间;如果是稠密图,考虑到邻接表中要附加链域,我们一般用邻接矩阵来存储

邻接表的创建

#include <iostream>
#include <cstring>
using namespace std;

class Graph {
private:
int **mat;
int n;

public:
Graph(int input_n) {
n = input_n;
mat = new int*
;
for (int i = 0; i < n; ++i) {
mat[i] = new int
;
memset(mat[i], 0, sizeof(int) * n);
}
}

~Graph() {
for (int i = 0; i< n; ++i) {
delete[] mat[i];
}
delete[] mat;
}

void insert(int x, int y) {
mat[x][y]=1;
}

void output() {
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cout<<mat[i][j]<<" ";
}
cout<<endl;
}

}
};

int main() {
int n, m, x, y;
cin >> n >> m;
Graph g(n);
for (int i = 0; i < m; ++i) {
cin >> x >> y;
g.insert(x, y);
}
g.output();
return 0;
}


邻接表

#include <iostream>
using namespace std;

class LinkedListNode {
public:
int vertex;
LinkedListNode *next;

LinkedListNode(int vertex_input) {
vertex = vertex_input;
next = NULL;
}
};

class LinkedList {
public:
LinkedListNode *head;

LinkedList() {
head = NULL;
}

~LinkedList() {
while (head != NULL) {
LinkedListNode *delete_node = head;
head = head->next;
delete delete_node;
}
}

void insert(int vertex) {
LinkedListNode *node = new LinkedListNode(vertex);
node->next = head;
head = node;
}
};

class Graph {
private:
LinkedList *edges;
int n;
public:
Graph(int input_n) {
n = input_n;
edges = new LinkedList
;
}

~Graph() {
delete[] edges;
}

void insert(int x, int y) {
edges[x].insert(y);
}

void output() {
for(int i=0;i<n;i++){
cout<<i<<":";
for(auto j=edges[i].head;j!=NULL;j=j->next){
cout<<j->vertex<<" ";
}
cout<<endl;
}
}
};

int main() {
int n, m, x, y;
cin >> n >> m;
Graph g(n);
for (int i = 0; i < m; ++i) {
cin >> x >> y;
g.insert(x, y);
}
g.output();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: