图是由一组顶点和一组能够将两个顶点相连的边组成的(可以无边,但是至少包含一个顶点):
[外链图片转存失败(img-SuflOrhS-1566875437171)(https://github.com/PandaHigh/image/blob/master/baseMean.png?raw=true)]
[外链图片转存失败(img-D96KImJe-1566875437172)(https://github.com/PandaHigh/image/blob/master/DirectedGraphAndUndirectedGgraph.png?raw=true)]
图可以分为无向图和有向图:
[外链图片转存失败(img-r8s4gSHR-1566875437173)(https://github.com/PandaHigh/image/blob/master/connectedGraph.png?raw=true)]
图还可以分为连通图和非连通图:
使用一个V乘以V的布尔矩阵, 当顶点v和顶点w之间有相连接的边时,定义布尔矩阵的第v行第w列的元素值为true,顶点与顶点之间没有相连接则定义为false.
使用一个以顶点为索引的列表数组,对于数组的每个位置都存储着一条与该顶点相连接的顶点构成的链表
例如在无向无权图中的:
在无向有权图中 :
在有向无权图中:
邻接矩阵与邻接矩阵对比:
基本思路 : 深度优先搜索遍历图的方法是,从图中某个顶点出发
[外链图片转存失败(img-XdljOIIF-1566875437176)(https://github.com/PandaHigh/image/blob/master/depthFirstSearch.png?raw=true)]
使用深度优先搜索查找图中的路径:
/** 深度优先搜索查找图中的路径 */
public class DepthFirstPaths {
private boolean[] marked;//这个顶点是否已被访问
private int[] edgeTo;//从起点到一个顶点的已知路径上的最后一个顶点
private int s;//搜索起点
public DepthFirstPaths(Graph G, int s){
marked=new boolean[G.V()];
edgeTo=new int[G.V()];
this.s=s;
dfs(G,s);
}
/**
* 深度优先搜索
* @param G 要搜索的图
* @param v 搜索顶点
*/
private void dfs(Graph G,int v){
marked[v]=true;
for (int w : G.adj(v)) {
if(!marked[w]){
edgeTo[w]=v;
dfs(G,w);
}
}
}
/**
* 是否有路径可以到达v
* @param v 要到达的顶点
* @return 有路径可以到达v为true,反之为false
*/
public boolean hasPathTo(int v){
return marked[v];
}
/**
* 从起点s到达v顶点的路径
* @param v 要到达的顶点
* @return 路径
*/
public Iterable pathTo(int v){
if(!hasPathTo(v)){
return null;//没有找到顶点v
}
Stack path = new Stack<>();//从终点v到起点s挨个压入栈中
for(int x=v;x!=s;x=edgeTo[x]){
path.push(x);
}
path.push(s);
return path;
}
}
基本思路 : 广度优先搜索,维护了一条队列
使用广度优先搜索查找图中顶点路径 :
/** 广度优先搜索查找图中的路径 */
public class BreadthFirstPaths {
private boolean [] marked;//这个顶点是否已被访问
private int[] edgeTo;//从起点到一个顶点的已知路径上的最后一个顶点
private int s;//搜索起点
public BreadthFirstPaths(Graph G,int s){
marked=new boolean[G.V()];
edgeTo=new int[G.V()];
this.s=s;
bfs(G,s);
}
/**
* 广度优先搜索
* @param G 要搜索的图
* @param s 搜索起点
*/
private void bfs(Graph G,int s){
Queue queue = new Queue<>();
marked[s]=true;
queue.enqueue(s);
while(!queue.isEmpty()){
int v=queue.dequeue();
for (Integer w : G.adj(v)) {
if(!marked[w]) {
marked[w] = true;
edgeTo[w] = v;
queue.enqueue(w);
}
}
}
}
/**
* 从起点s到达v顶点的路径
* @param v 要到达的顶点
* @return 路径
*/
public Iterable pathTo(int v){
if(!hasPathTo(v)){
return null;
}
Stack path = new Stack();
for(int x=v;x!=s;x=edgeTo[x]){
path.push(x);
}
path.push(s);
return path;
}
}
深度优先搜索就像是一个人在走迷宫,不撞南墙不回头
而广度优先搜索就像是一组警察在搜查犯人,同时往不同的方向搜寻.
图论算法(一)深度优先搜索与广度优先搜索
图论算法(二)最小生成树
图论算法(三)最短路径