下面程序中的图是按邻接链表实现的
BFS(广度优先遍历)顾名思义,在把距离源点s的所有点找完后,才会去找距离源点s+1的点。该算法计算的是从源点到其它点最少的边数。程序中使用了队列来保证按规则遍历结点,BFS基本就是按《算法导论》伪代码实现的。书中伪代码的时间复杂度为O(V+E),但是初始化在创建结点时就完成了,所以下面的代码时间复杂度为O(E),其实算法导论书上的BFS同时完成了无权图的单源最短路径问题,因为它带有与源点的距离这个属性
DFS(深度优先遍历),即尽可能在图中深入遍历,对最近刚发现的点进行遍历,程序中通过栈实现(后进先出),DFS中结点有2个时间戳,简单解释就是结点首次被发现的时间和该结点的邻点全被发现的时间,DFS时间复杂度也为O(V+E),代码如下:
import java.awt.Color;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Stack;
public class BFSandDFStest {
public static int time = 0;//DFS用的,由于是结点共同的,所以在这设置了全局变量
public static void main(String[] args) {
Map<Vertex,List<Vertex>> G = new HashMap<>();//用map映射来完成图
//各个结点的邻接节点
List<Vertex> aAdj = new LinkedList<>();
List<Vertex> bAdj = new LinkedList<>();
List<Vertex> cAdj = new LinkedList<>();
List<Vertex> dAdj = new LinkedList<>();
List<Vertex> eAdj = new LinkedList<>();
//图中的各个结点
Vertex A = new Vertex("A");
Vertex B = new Vertex("B");
Vertex C = new Vertex("C");
Vertex D = new Vertex("D");
Vertex E = new Vertex("E");
//各个点连接各自邻点
aAdj.add(B);aAdj.add(D);
bAdj.add(C);
cAdj.add(D);cAdj.add(E);
dAdj.add(C);dAdj.add(E);
//把结点放入图中
G.put(A, aAdj);
G.put(B, bAdj);
G.put(C, cAdj);
G.put(D, dAdj);
G.put(E, eAdj);
BFS(G, A);//从A开始遍历
DFS(G, A);
}
public static void BFS(Map<Vertex, List<Vertex>> G, Vertex A) {
A.color = Color.GRAY;
A.d = 0;
Queue<Vertex> Q = new LinkedList<>();//队列是接口
Q.add(A);
while(!Q.isEmpty()) {
Vertex u = Q.poll();//取出一个节点
for (Vertex v : G.get(u)) {//取出节点u的所有邻接节点
if(v.color == Color.WHITE) {//只有未被发现才执行下面的语句
v.color = Color.GRAY;
v.d = u.d + 1;
v.p = u;
Q.add(v);
}
}
u.color = Color.BLACK;//u的所有邻接节点都变灰色了,u变黑
}
for (Vertex k : G.keySet()) {
System.out.println("BFS后"+k+"点距离A为"+k.d);
}
}
public static void DFS(Map<Vertex, List<Vertex>> G, Vertex A) {
//由于BFS运行了,在这里初始化
for (Vertex k : G.keySet()) {
k.color = Color.WHITE;
k.d = Integer.MAX_VALUE;
k.p = null;
}
//从A开始
DFSVisit(G, A);
//以防有从A开始到不了的点,必须还有个循环
// for (Vertex k : G.keySet()) {
// //System.out.println(k);
// if(k.color==Color.WHITE)
// DFSVisit(G,k);
// }
//查看DFS后各点信息
for (Vertex k : G.keySet()) {
System.out.println(k.key + k.d + "/" + k.f);
}
}
public static void DFSVisit(Map<Vertex, List<Vertex>> G, Vertex A) {
A.d = ++time;
A.color = Color.GRAY;
Stack<Vertex> S = new Stack<>();
S.push(A);
while(!S.isEmpty()) {
Vertex u = S.peek();//只看不取,因为深度优先一轮一般不会变黑,不能取出来
Vertex v = getAdj(G,u);//取处于栈顶的节点的一个非白邻点
//可能没邻点或无非白邻点,有执行if后语句压栈,无执行else的描黑并出栈
if(v != null) {
v.color = Color.GRAY;
v.d = ++time;
v.p = u;
S.push(v);
}else {
u.color = Color.BLACK;
u.f = ++time;
S.pop();
}
}
}
public static Vertex getAdj(Map<Vertex,List<Vertex>> G,Vertex u) {
for (Vertex v : G.get(u)) {
if(v.color == Color.WHITE)
return v;
}
return null;
}
}
class Vertex{//图的结点类
String key;
Color color;//颜色用来表示结点的状态,白色代表未被发现,灰色代表未被完全发现,黑色代表完全发现
int d;//BFS中代表与源的距离(边数),DFS中代表被发现时的时间戳
int f;//DFS中代表变黑时的时间戳
Vertex p;//父亲或者前驱结点
public Vertex(String key) {
this.key = key;
color = Color.WHITE;
d = Integer.MAX_VALUE;//初始距离源点为无限远
p = null;
f = 0;
}
public int hashCode() {//hashmap必须实现
return key.hashCode();
}
public String toString() {
return key;
}
public boolean equals(Object o) {//hashmap必须实现
if(o == null || !(o instanceof Vertex) )
return false;
if(o == this)
return true;
return key.equals(((Vertex)o).key);
}
}