简单来说,仅仅是一个边和两个顶点之间的连接

图片

这份API包含两个构造函数,分别接受一个整数,并常见一个包含整数个数的图

第二个构造函数,接受输入由2e+1个整数组成,显示V,E,然后E对 V-1之间的整数

图片

前两个分别代表了,V和E,构成如上的图

图的实现可以考虑如下的几种方式

1.邻接矩阵:使用一个V乘以V的布尔矩阵,当顶点v和顶点w之间有相连接的边时,定义v行w列的元素为true

但是其占用空间过大,无法满足

2.边的数组:使用一个Edge类,含有两个int实例变量,但是这种方式实在不符合adj的方法实现,如果这样写,每次查找都会遍历一边图

3.邻接表数组:一个以顶点为索引的列表数组,其中每个元素都是和顶点相邻的顶点列表,这是最符合的

实现如下

图片

使用多维数组实现如上的方式进行测试
图片

每个顶点后的相邻表,可以使用集合实现

对应的添加一条边,是在在V-W之间添加一个边,会在V的相邻表中添加W,W的相邻表中添加V

其性能特点:

使用的空间和V+E成正比

添加一条边的时间控制在常数呢

遍历顶点V的所有相邻顶点和所需的时间和V的度数成正比(处理每个相邻顶点时间皆为常数)

但仍需要注意,插入顺序决定了在表中的出现顺序,故要严格保证出现顺序

public Graph(int V) {

this.V = V;//赋值过去

this.E = 0;

adj = (Bag2<Integer>[]) new Bag2[V]; //创建一个链表

for (int i = 0; i < adj.length; i++) {

adj[i] = new Bag2<Integer>();

}

}

public Graph(InputStream input) throws IOException {

this(input.read());

int E = input.read();//读取

for (int i = 0; i < E; i++) {

int v = input.read();

int w = input.read();

addEdge(v, w);

}

}

public void addEdge(int v, int w) {

adj[v].add(w);

adj[w].add(v);//相互添加

E++;

}

这两个构造方法分别利用图和整形来创建图

这里面每插入一对v-w顶点,都会插入两次

还有其他的操作也很常见,添加一个顶点和删除一个顶点

这样的简单实现的可能性为使用符号表来代替数组

之后在进行扩展API

删除一条边,检查图中是否含有边V-W

实现了基本的图,我们来看下常见的无向图API如下

图片

然后关于无环图,还有一个顺序的搜索每一个边

如何避免可能会出现的重复搜索

图片

搜索相关的API如下

图片

对于这个搜索,我们需要引入递归这个概念

简单来说就是,在访问一个结点的时候,把这个节点标记为已经访问

递归的访问没访问的邻居结点

比如深度优先遍历

图片

利用递归的方法,依次查找,如果邻接表内都已经被标记了,返回上一层,进行下一个,依次直到没有没被标记的

利用这种递归,我们能够解决很多有效的处理很多和图相关的任务

例如:

两个给定的顶点是否连通,图中还有多少个连通子图

或者给定一个起点s,从s到给定目的顶点v之间是否存在一个路径

图片

其次是广度遍历优先

深度优先类似一个人在迷宫之中进行探索,而广度优先就像一个探索队,遇到一个岔路,就分成两个

然后再岔路后相遇,就合并

在深度遍历之中,我们调用了一个下压栈,使用后进先出的规则来描述

在广度遍历之中,我们使用了队列即可,选择最早遇到的那条

图片

我们先把0加入进去队列

然后把删除0把他的相邻结点 2  1  5 加入进去,把这几个的结点edgeTo[]的值设置为0

然后删除 2 ,把他的相邻结点,把 1 5 3 4 加进去,但是 1 5 已经标记了,所以我们只能把 3 4结点edgeTo[]设置为1

剩下的按顺序添加,然后按顺序检查是否标记了,然后依次删除

图片

最后的最后,我们看一下几个实现的特殊功能

比如查找一个图中有多少个连通树

图片

实现思路:

获取一个图,然后按照图的顺序,先读取按照索引,深度遍历其连通的顶点,给每个顶点都做上相同的标记.查询完成(没有再连通的),循环进行下一个查找,如果没有被遍历,就说明是新的连通树

在进行深度遍历,给其上每个顶点都做上相同标记

图片

发表评论

邮箱地址不会被公开。 必填项已用*标注