图的基本知识及实现_邻接矩阵_邻接表
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}vj之间有边,则可认为顶点 v_{i}vi到 v_{j}vj有边,同时顶点 v_{j}vj到 v_{i}vi 也有边。对应到邻接矩阵里,
则有
A[i][j]=A[j][i]=1。
因此我们可以发现,无向图的邻接矩阵是一个对称矩阵。
在邻接矩阵上,我们可以直观的看出两个顶点之间是否有边(或弧),并能容易求出每个顶点的度,入度和出度。
这里我们以图 G_{1}G1为例,演示下如何利用邻接矩阵计算顶点的入度和出度。顶点的出度,即为邻接矩阵上点对应行上所有值的总和,比如顶点 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 个顶点的图,邻接矩阵总是需要n2的存储空间。当边数很少的时候,就会造成空间的浪费。
因此,具体使用哪一种存储方式,要根据图的特点来决定:如果是稀疏图,我们一般用邻接表来存储,这样可以节省空间;如果是稠密图,考虑到邻接表中要附加链域,我们一般用邻接矩阵来存储
邻接表的创建
邻接表
A[i][j] = 1,
否则 A[i][j] = 0。
下图为有向图 G_{1}G1
以及对应的邻接矩阵。
下图为无向图 G_{2}G2
以及对应的邻接矩阵。
图的邻接矩阵是唯一的,矩阵的大小只与顶点个数 NN 有关,是一个 N * NN∗N 的矩阵。前面我们已经介绍过,在无向图里,如果顶点 v_{i}vi
v_{j}vj之间有边,则可认为顶点 v_{i}vi到 v_{j}vj有边,同时顶点 v_{j}vj到 v_{i}vi 也有边。对应到邻接矩阵里,
则有
A[i][j]=A[j][i]=1。
因此我们可以发现,无向图的邻接矩阵是一个对称矩阵。
在邻接矩阵上,我们可以直观的看出两个顶点之间是否有边(或弧),并能容易求出每个顶点的度,入度和出度。
这里我们以图 G_{1}G1为例,演示下如何利用邻接矩阵计算顶点的入度和出度。顶点的出度,即为邻接矩阵上点对应行上所有值的总和,比如顶点 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 个顶点的图,邻接矩阵总是需要n2的存储空间。当边数很少的时候,就会造成空间的浪费。
因此,具体使用哪一种存储方式,要根据图的特点来决定:如果是稀疏图,我们一般用邻接表来存储,这样可以节省空间;如果是稠密图,考虑到邻接表中要附加链域,我们一般用邻接矩阵来存储
邻接表的创建
#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; }
相关文章推荐
- 渗透技术一瞥(图)
- 图片引发的溢出危机(图)
- C++实现图的邻接矩阵存储和广度、深度优先遍历实例分析
- C++实现图的邻接表存储和广度优先遍历实例分析
- jQuery圆形统计图开发实例
- 手机短信轰炸(图)
- C语言实现图的遍历之深度优先搜索实例
- python数据结构之图的实现方法
- ASP.Net页面生成饼图实例
- 基于Java实现的图的广度优先遍历算法
- RelativeLayout浅谈
- 图
- Ext Scheduler Web资源甘特图控件
- 键盘码 图
- 图(1)——图的定义和基本概念
- 图(2)—— 邻接矩阵表示法
- 图(2)—— 邻接矩阵表示法
- 图(3)——邻接链表法
- 图(3)——邻接链表法
- Linux学习笔记:基础知识学习整理【图】