数据结构:图

数据结构:图

Eclipse java工程: 图的深度优先遍历、广度优先遍历
demo:http://download.csdn.net/detail/keen_zuxwang/9875848

线性表、树、图数据结构:
线性表中的元素是“一对一”的关系
树中的元素是“一对多”的关系
图中的元素则是“多对多”的关系
图(Graph)是一种复杂的非线性结构,在图结构中,每个元素都可以有零个或多个前驱,也可以有零个或多个后继(即元素之间的关系是任意的). 图的数据结构和算法都比较复杂


图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为G(V,E):
G表示一个图,
V是图G中顶点的集合,
E是图G中边的集合

1、图的分类、度、路径长度
图是按照无方向和有方向分为:
无向边:顶点间的边没有方向
有向边(弧):顶点间边有方向
无向图:是由顶点和无向边构成(图中任意两个顶点间的边都是无向边)
有向图:是由顶点和弧(有向边)构成,弧有弧头和弧尾区别
完全无向图: 任意两个顶点之间都存在无向边,若有n个顶点的无向图有n(n-1)/2 条边, 则此图为完全无向图。
完全有向图: 任意两个顶点之间都存在有向的边,有n个顶点的有向图有n(n-1)条边, 则此图为完全有向图
简单图:如果无重复的边或者顶点到自身的边
网:边带权值的图
连通图:图中任意两个顶点都是连通的
按照边分为:(这是个模糊的概念,同样是相对的概念)
稀疏图
稠密图
(图中顶点之间有邻接点)

数学方式表示时:

无向边:()表示
无向图,连接顶点A与D的边,可以表示为无序对(A,D),也可以写成(D,A)
有向边:<>表示
有向图,连接顶点A到D的有向边就是弧,A是弧尾,D是弧头,<A,D>表示弧(有序的),不能写成<D,A>

顶点的度:
顶点关联边的数目。有向图图中有入度、出度(在有向图中顶点的度就是入度和出度之和):
入度:方向指向顶点的边
出度:方向背向顶点的边

路径长度:
路径上边或者弧的数目

2、连通图:
在图论中,连通图基于连通的概念,图的连通性是图的基本性质。
在无向图G中,若从顶点vi到顶点vj有路径相连(当然从vj到vi也一定有路径),则称vi和vj是连通的。如果G是有向图,那么连接vi和vj的路径中所有的边都必须同向。
如果图中任意两点都是连通的,那么图被称作连通图。如果此图是有向图,则称为强连通图(需要双向都有路径)

对一个图G=(V,E)中的两点x和y ,若存在交替的顶点和边的序列Γ=(x=v0-e1-v1-e2-…-ek-(vk+1)=y) (在有向图中要求有向边vi?( vi+1)属于E ),
则两点 x 和 y 是连通的。
Γ是一条x到y的连通路径,x和y分别是起点和终点。当x =y 时,Γ被称为回路。
如果通Γ中的边两两不同,则Γ是一条简单通路,否则为一条复杂通路。如果图G中每两点间皆连通,则G是连通图

连通分量:
无向图G的一个极大连通子图称为G的一个连通分量(或连通分支)。
连通图只有一个连通分量,即其自身
非连通的无向图有多个连通分量
强连通图:
有向图G=(V,E)中,若对于V中任意两个不同的顶点x和y,都存在从x到y以及从y到x的路径,则称G是强连通图。
强连通分量:强连通图只有一个强连通分量,即是其自身
非强连通的有向图有多个强连分量
单向连通图:
G=<V,E>是有向图,如果u->v意味着图G至多包含一条从u到v的简单路径,则图G为单连通图。
弱连通图:
将有向图的所有的有向边替换为无向边,所得到的图称为原图的基图。如果一个有向图的基图是连通图,则有向图是弱连通图。
初级通路:
通路中所有的顶点互不相同。初级通路必为简单通路,但反之不真。

连通图性质:
一个无向图 G=(V,E) 是连通的,那么边的数目大于等于顶点的数目减一:|E|>=|V|-1,而反之不成立。
G=(V,E)是有向图,那么它是强连通图的必要条件是边的数目大于等于顶点的数目:|E|>=|V|,而反之不成立。
没有回路的无向图是连通的当且仅当它是树,即等价于:|E|=|V|-1。

3、图的存储结构
图的结构比价复杂,任意两个顶点之间都可能存在关系,不能用简单的顺序存储结构来表示,存储结构分为邻接矩阵、邻接表、十字链表、邻接多重表、边集数组
(1)、邻接矩阵:
图的邻接矩阵存储方式是用两个数组来表示图:
顶点数组(顶点表):一个一维数组存储图中顶点信息
边数组(边表):一个二维数组(邻接矩阵)存储图中的边或弧的信息

无向图的边数组是一个对称矩阵。对称矩阵就是n阶矩阵的元满足aij = aji。即从矩阵的左上角到右下角的主对角线为轴,右上角的元和左下角相对应的元全都是相等的。
从邻接矩阵,很容易知道图中的信息。
1)0表示无边,1表示有边–很容易判断任意两顶点是否有边
2)顶点的度是行内数组元素之和:就是这个顶点vi在邻接矩阵中第i行或(第i列)的元素之和
3)求顶点邻接点,将行内元素遍历下:求顶点vi的所有邻接点就是将矩阵中第i行元素扫描一遍,arc[i][j]为1就是邻接点

有向图的邻接矩阵:
顶点的入度、出度:
入度:各列之和
出度:各行之和

邻接矩阵的有向图和无向图数据结构相同,
其中无向图的邻接矩阵是对称的所以可以采用三角矩阵进行压缩存储,其存储空间只需n(n+1)/2,而有向图则需要n*n

(2)、邻接表:
找到一种数组与链表相结合的存储方法称为邻接表—对于边数相对顶点较少的图,比邻接矩阵节省存储空间。
邻接表无向图和有向图数据结构相同,只是有向图需要出边表和入边表两张表来表示边之间的关系
顶点表:一维数组存储/单链表来存储,数组可以较容易的读取顶点的信息,更加方便。
线性表(边表):图中每个顶点vi的所有邻接点构成,由于邻接点的个数不定,用单链表存储,
无向图称为顶点vi的边表
有向图则称为顶点vi作为弧尾的出边表

顶点表结点:data和firstedge两个域组成
data firstedge
data是数据域,存储顶点的信息
firstedge是指针域,指向边表的第一个结点,即此顶点的第一个邻接点。

边表结点:adjvex和next两个域组成
adjvex weight next
adjvex是邻接点域,存储某顶点的邻接点在顶点表中的下标,
next则存储指向边表中下一个结点的指针。
对于带权值的网图,可以在边表结点定义中再增加一个weight的数据域,存储权值信息即可

有向图也可以用邻接表:出度表叫邻接表,入度表尾逆邻接表

(3)、十字链表:
就是把邻接表和逆邻接表结合起来的。对于有向图来说,邻接表是有缺陷的。关心了出度问题,想了解入度就必须要遍历整个图才知道,逆邻接表解决了入度却不了解出度情况。
它为有向图的优化存储结构。

顶点表结点:
data firstin firstout
firstin表示入边表头指针,指向该顶点的入边表中第一个结点
firstout表示出边表头指针,指向该顶点的出边表中的第一个结点

边表结点:
headvex tailvex headlink taillink
headvex是指弧起点在顶点表的下表
tailvex是指弧终点在顶点表的下标
headlink是指入边表指针域,指向起点相同的下一条边
taillink是指出边表指针域,指向终点相同的下一条边。
如果是网,还可以增加一个weight域来存储权值

十字链表的好处就是因为把邻接表和逆邻接表整合在一起,
既容易找到以v为尾的弧,
也容易找到以v为头的弧,
因而比较容易求得顶点的出度和入度。

而且除了结构复杂一点外,其实创建图算法的时间复杂度是和邻接表相同的,在有向图应用中,十字链表是非常好的数据结构模型。

(4)、邻接多重表
顶点表结点:data和firstedge两个域组成
data firstedge
data是数据域,存储顶点的信息
firstedge是指针域,指向边表的第一个结点,即此顶点的第一个邻接点。
邻接多重表结构(边表):(对于无向图的邻接表进行优化)
ivex ilink jvex jlink
ivex和jvex是与某条边依附的两个顶点在顶点表中的下标。
ilink指向依附项点ivex的下一条边,
jlink指向依附顶点jvex的下一条边。

邻接多重表与邻接表的差别:仅仅是在于同一条边在邻接表中用两个结点表示,
而在邻接多重表中只有一个结点

(5)、边集数组
边集数组侧重于对边依次进行处理的操作,而不适合对顶点相关的操作
边集数组是由两个一维数组组成,
顶点表:存储顶点的信息
边表:存储边的信息,是边的集合。这个边数组中每个数据元素由一条边的起点下标(begin)、
终点下标(end)和权重(weight)组成
边数组结构:
begin end weight
begin存储起点下标、end存储终点下标、weight存储权重

4、图的遍历:
和树的遍历类似,希望从图中某一顶点出发访遍图中其余顶点,且使每一个顶点仅被访问一次,这一过程就叫图的遍历。分为深度优先遍历、广度优先遍历

深度优先遍历(深度优先搜索)DFS: 就像是一棵树的前序遍历
它的思想:
假设初始状态是图中所有顶点均未被访问,则从某个顶点v出发,首先访问该顶点,然后依次从它的各个未被访问的邻接点出发深度优先搜索遍历图,
直至图中所有和v有路径相通的顶点都被访问到。 若此时尚有其他顶点未被访问到,则另选一个未被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止
简言之,任取一未被访问顶点A,在ENode表中找出未被访问的顶点B,然后再找B中未被访问的顶点C,依此循环

广度优先遍历(广度优先搜索)BFS: 图的广度优先遍历类似于树的层序遍历
它的思想是:
从图中某顶点v出发,在访问了v之后依次访问v的各个未曾访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,
并使得“先被访问的顶点的邻接点先于后被访问的顶点的邻接点被访问,直至图中所有已被访问的顶点的邻接点都被访问到。如果此时图中尚有顶点未被访问,
则需要另选一个未曾被访问过的顶点作为新的起始点,重复上述过程,直至图中所有顶点都被访问到为止。
简言之,任取顶点A,依次访问A的邻接表中的各个顶点(BCD),再从B出发依次访问B的邻接表中的所有顶点,依此循环。

对比图的深度优先遍历与广度优先遍历算法,它们在时间复杂度上是一样的,
不同之处仅仅在于对顶点的访问顺序不同。可见两者在全图遍历上是没有优劣之分的,只是不同的情况选择不同的算法

最小生成树——prim算法
算法简单描述:
首先选一顶点A,找出A的最小权值两栖边B,将B加入A的集合,再找AB中的最小两栖边,依此找最小两栖边,直到所有顶点被并入A的集合。
两栖边:
设V是一个图的顶点集合,U是V中的一个非空真子集(即U中有元素),U中顶点和非U中顶点(即V-U)的连接边称为两栖边

最小生成树——Kruskal算法(克鲁斯卡尔算法,边集数组)
基本思想:按照权值从小到大的顺序选择n-1条边,并保证这n-1条边不构成回路。
具体做法:首先构造一个只含n个顶点的森林,然后依权值从小到大从连通网中选择边加入到森林中,并使森林中不产生回路,直至森林变成一棵树为止

最短路径——Dijkstra算法
迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径。
它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止。。
基本思想
通过Dijkstra计算图G中的最短路径时,需要指定起点s(即从顶点s开始计算)。此外,引进两个集合S和U。
S的作用是记录已求出最短路径的顶点(以及相应的最短路径长度),而U则是记录还未求出最短路径的顶点(以及该顶点到起点s的距离)。
初始时,S中只有起点s;U中是除s之外的顶点,并且U中顶点的路径是”起点s到该顶点的路径”。
然后,从U中找出路径最短的顶点,并将其加入到S中;接着,更新U中的顶点和顶点对应的路径。
然后,再从U中找出路径最短的顶点,并将其加入到S中;
接着,更新U中的顶点和顶点对应的路径。
… 重复该操作,直到遍历完所有顶点

拓扑排序
拓扑排序(Topological Order)是指,将一个有向无环图(Directed Acyclic Graph简称DAG)进行排序进而得到一个有序的线性序列。
例如,一个项目包括A、B、C、D四个子部分来完成,并且A依赖于B和D,C依赖于D。现在要制定一个计划,写出A、B、C、D的执行顺序。这时,就可以利用到拓扑排序,它就是用来确定事物发生的顺序的。
在拓扑排序中,如果存在一条从顶点A到顶点B的路径,那么在排序结果中B出现在A的后面。

最小生成树:找出连接所有顶点的最优解
最短路径:找出两个顶点路径的最优解
拓扑排布:AOV网中顶点间存在前驱后继的关系,它是确定事件的进程,如制定学生学习计划,安排施工进程等。
图的算法还有:关键路径,Floyd等

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值