图论(1) 图的基本数据结构和算法

图论(1) 图的基本数据结构和算法


图里面的东西太多,先写一个概要。在后面的文章中将继续逐个探讨和实现。

1,一些概念

顶点

边(无向图) 或 弧(有向图)

完全图,子图,连通图

路径,简单路径(顶点不重复)

生成树(无向图),关键路径,拓扑排序


2,存储结构

非常重要!!!
2种存储方式,邻接矩阵和邻接表

目前我写的都是用邻接表写的,但后来发现大家还是用邻接矩阵比较多,后来问了下baidu的阿海,他说一般都是用邻接矩阵,简单一些,但用过邻接表话,肯定可以秒杀邻接矩阵。恩,有时间我也写一下邻接矩阵的实现,,,,


无论哪种方式,顶点一般来说都放在数组里。(当然你也可以放在链表里,这样似乎很麻烦,很少见到这样做的),两种方式的区别在于顶点之间的关系的实现用什么

1)邻接表

这里的表其实是存储边得链表。

将顶点放在一个Node[]数组里,每一个顶点维护一个它的边的链表(想想怎么去实现?),下面是顶点类的定义:

package Graph;

public class VNode {

    privateObject element;        //节点自身信息
    private Edge firstEdge;            //节点的第一条边
    private boolean visited = false;    //在遍历时标识是否被访问过
   
    //get,set方法省略
}


每次写一个类似于C里面的结构体类,都把成员变量写为private,结果就需要写很多的get和set方法来访问和设置,这样做符合面向对象封 装的要求,但算法的代码就显得比较麻烦,为了简化代码,侧重算法,以后我就都把它们写成public了。这里还是写成了private,get和set方 法省略了。

这样Node[]数组里存放的就是上述顶点类型,每一个顶点包含顶点自身存放元素的信息(必备),是否被访问过的信息(遍历时用到),指向第一条边的Edge指针,


要维护顶点的边链表,还需要一个边类:

package Graph;

public class Edge {
   
    private int start,end;    //边指向两个节点的位置(如果用数组存放节点,就是下标,如果用链存放下标,就是位置索引)
    private Edge next;                //边指向的下一条边
   
    private int len;                //边的信息(长度)   
   
      
       //省略读写方法
}



我用边得首尾顶点在顶点数组里的下标来标识一条边(这样有向无向图可以一起写),在边里还要维护一个指向下一个边的Edge指针(维护边链表),还有一个边的长度信息(写最小生成树的时候用到,或者其他的加权图)


上述2个顶点和边的定义就可以实现邻接表的存储方式。


2)邻接矩阵

现在顶点的定义只需要放顶点的元素和是否被访问即可,不需要指向第一个边的指针。

我们还是用Node[]放顶点,用一个关系矩阵来存放顶点之间的关系(是否有边连接)
关系矩阵用一个二维数组实现,


M[n][n]---假设有n个顶点的关系矩阵,M[i][j]的值表示顶点i和顶点j的关系



3,基本的算法

1)广度优先搜索
队列实现

2)深度优先搜索
栈实现

3)无向图的最小生成树
2种贪心算法

4)拓扑排序

5)带权有向无环图的关键路径

6)最短路径



总结:

图的存储方式很重要,弄清楚怎么去标表示图,才能做接下来的工作---

邻接表是指每个顶点维护一个跟它相关联的边得链表,而不是跟它相关联的顶点的链表,也就是说需要有2个类,顶点类(要包含指向第一个关联边的引用),边类(要包含指向下一条关联边得指针)。如果只有顶点类的话,那不行,边的长度信息没有地方存储。

这是用邻接表的时候的一个小思考和误区,如果实现成相关联的顶点的链表,那么只能做广搜和深搜,对于加权图有关的算法就无能为力了,这样实现只能表示顶点之间的是否有连接的关系,边的信息不存在。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值