Data Structure: 图 (Graph)

图的定义:

 

图的组成元素是:顶点和边。对于有向图而言,还有方向。然而,图的最基本的要求是,顶点的结合一定是非空。不同于空链表和空树。并没有空图的说法。但边集可以是空。

 

一些定义:

 

1、简单图:任何一个顶点不能通过边回到自己,且同一条边不能重复地出现。

 

2、有向边和无向边的不同表示方法:无向边用() 小括号表示,(A,D),用尖括号表示有向边<A,D>. 在数据结构中,无向图其实是一种特殊的有向图,每一条无向边其实是双向的有向边。

 

3、如果有一个无向图的任意两个顶点有边相连,则成为无向完全图。无向完全图的顶点数和边数的关系是:n*(n-1)/2。(n是顶点数)

 

4、如果有一个有向图,任意两个顶点都有来回的两条边相连,则是有向完全图。顶点数和边数的关系是:m = n*(n-1)。一般在图论中,n可以作为vertex数,m是边数。

 

5、对于无向图而言,顶点的度(degree)是和顶点相关联的边的数目。对于有向图而言,顶点的入度(InDegree)是箭头指向自己的边的数目。出度(OutDegree)则是从自己这里出去的边的数目。InDegree是很有用的在topo sort里面。

 

术语:

 

在无向图中,如果从一个顶点a到另外一个顶点b有路径,则a和b是连通的。而如果一幅图(包括有向和无向的),任意两个顶点间是相互连通的,则称这幅图是连通图。树其实是一种特殊的连通图,无环连通图。

 

图的存储结构:

 

总体而言,图的存储结构有三种:邻接矩阵、邻接表和十字链表、多重邻接表以及邻接边集。

 

由于普遍的编程题以邻接链表和邻接矩阵为主。邻接矩阵其实更多用于稠密图 m = n ^ 2,而邻接链表更常用,在n 和 m一个数量级的sparse graph. 

 

1、邻接矩阵 (adjacency matrix):

 

用两个矩阵来存储一个图。顶点用一维矩阵,而边用二维矩阵。如图【1】:

 

 

矩阵的元素代表当前的行和列代表的顶点之间有没有边相连。(0没有,1有)。

 

如果在Dijkstra算法来求单源最短路(所有权重都是正数)的问题,adjunct matrix的值存的是权重。

 

2)邻接表 (adjacency list)

 

上述的邻接矩阵的问题在于,如果遇到了稀疏图(顶点多,边少),则造成了极大的空间浪费。正如考虑树的存储结构时,考虑使用链表的最大好处就是节约不必要的空间浪费。

 

所以,图也可以使用顶点数组 + 链表的方式存储。

 

 

通常在编程题的用一个一维数组代表顶点。然后对应每一个顶点一个单链表,把所有的邻接的点串起来。

 

用数组来模拟链表,更而模拟邻接链表的模板:

 

const int N = 100010, M = 2 * N;

int h[N], e[M], ne[M], idx = 0;

void add(int a, int b) {
  ne[idx] = h[a];
  h[a] = idx;
  e[idx++] = b;
  // 如果是无向图的话,反方向还要再连连一下
}

 

图的遍历:

 

图的遍历是针对连通图而言的。对于连通图的基本技能就是,如何从任意一个节点出发,遍历整个图。

 

DFS:沿着确定的策略,坚持着一个劲走到底,直接走不了位置,再改变策略。当改变策略也发现都走过了,就返回,边返回边检查改变策略后有没有没有走过的。简而言之,二叉树的前序遍历就是一个特例。

 

一开始确定的策略是,沿着左孩子走,每到一个节点就打印当前值,接着向左子树走,走到叶子节点后,发现走不了了。回溯一层,还原现场,朝其他可能的方向继续往深的走。其它方向走完了,就返回再上一层父节点继续做同样的事情。一直这么回溯到根节点,检查完根节点(开始节点)改变策略的结果即可。

 

 

对应着图就是,从A节点出发,每次选择自己的右边,B - C - D- E -F,发现继续向右就到A了。改变策略,到G,向右到B,不行,向左,D?不行,所以再向左,H。到了H发现都走过了,回溯,G,检查,F,检查,E,检查,D,检查发现还有I没到过。所以,到I,I发现没路走了,返回D,返回C,检查,B检查,A检查。没有了没结束遍历。

 

所以DFS的顺序是:A - B - C - D - E - F - G - H - I .

 

对应两个不同的存储结构,DFS对于邻

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值