1、深度优先
尽快远离起始点
哭着闹着找到最远处的节点(所以,“深度优先” 可以理解为 “远度优先”)
1. 先访问起始点的 一个 邻居
2. 以此 邻居 为跳板,将 此邻居 的所有邻居都访问完成(当然,在访问 邻居的邻居 时候, 邻居的邻居的邻居 也要都被访问完成,最终的结果是 从此邻居向后,其实统统被访问过了)
3. 2 完成后,再回到起始点,然后访问起始点的 下一个 邻居
从这里的 1, 2, 3 中可以很明显的看出“远离起始点,尽量访问最远处的节点”
2、广度优先
水波纹扩展的过程(靠近自己的先都访问完)
先访问所有靠近自己的节点后,完成后才会再找外面一层
尽可能的靠近起始点
说实话,其实挺简单的。
大学时之所以学的那么苦,100% 还是因为当时没有那怕一丁点的编程基础。半点编程经验都没有,还要看复杂的一毛的 C/C++ 代码,也不知道偌大的教室里面是不是有个同学真的理解了。可能也有NB的哥们理解了吧,反正以我的智商实在做不到啊。
还好,这次自己补补吧,权当是儿童读物了,真的不算难
好了,把代码 paste 上吧,权当给自己作个记录,共四个文件:
Vertex.java
/**
* Describe the vertex in the graph
*
*/
public class Vertex {
private Object carryingInfo;
private boolean wasVisited;
public Object getCarryingInfo() {
return carryingInfo;
}
public void setCarryingInfo(Object carryingInfo) {
this.carryingInfo = carryingInfo;
}
public boolean isWasVisited() {
return wasVisited;
}
public void setWasVisited(boolean wasVisited) {
this.wasVisited = wasVisited;
}
public Vertex(Object carryingInfo) {
this.carryingInfo = carryingInfo;
wasVisited = false;
}
@Override
public String toString() {
return carryingInfo.toString();
}
}
Graph.java
public class Graph {
/**
* The maximal permitted count of vertices. The real vertices count is
* <code>nVerts</code>
*/
public static final int MAX_VERTEX = 20;
/**
* Matrix used to store the relationship among vertices.
*
* Some tailing rows and columns may be empty, the effective row/column
* count <code>nVerts</code>
*/
public int[][] adjMat = new int[MAX_VERTEX][MAX_VERTEX];
/**
* Array used to store each vertex
*
* The effective counts of this array is <code>nVerts</code>
*/
public Vertex[] arrayVertices = new Vertex[MAX_VERTEX];
/**
* Real vertices count
*/
public int nVerts;
public Graph() {
nVerts = 0;
for (int row = 0; row < MAX_VERTEX; row++) {
for (int column = 0; column < MAX_VERTEX; column++) {
adjMat[row][column] = 0;
}
}
}
public void addVertex(Object carryingInfo) {
Vertex v = new Vertex(carryingInfo);
arrayVertices[nVerts] = v;
nVerts++;
}
public void addEdge(int start, int end) {
adjMat[start][end] = 1;
adjMat[end][start] = 1;
}
public void removeEdge(int start, int end) {
adjMat[start][end] = 0;
adjMat[end][start] = 0;
}
public void displayVertex(Vertex v) {
System.out.println(v.getCarryingInfo());
}
}
SearchGraph.java
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Stack;
public class SearchGraph {
public static List<Object> dfs(Graph g) {
List<Object> listAccessOrder = new ArrayList<Object>();
// elements in it had already been visited
Stack<Vertex> stack = new Stack<Vertex>();
Vertex startVertex = pickFirstAccessVertex(g);
stack.push(startVertex);
startVertex.setWasVisited(true);
listAccessOrder.add(startVertex.getCarryingInfo());
System.out.println("Push into stack: " + startVertex);
while (!stack.empty()) {
Vertex topVertex = stack.peek();// This had already been visited. We
// peek it(not pop), and find one
// unvisited neighbour of it(Some
// neighbours had already been
// visited, but the other had not.
// So, we're going to find one of
// the unvisited neighbours)
// Find its next unvisted neighbour
Vertex unvisitedNeighbour = findOneUnVisitedNeighbour(g, topVertex);
// Yes, we find a vertex of this kind
if (unvisitedNeighbour != null) {
stack.push(unvisitedNeighbour);// (Of course, this new pushed
// one is the next peeked
// vertex)
unvisitedNeighbour.setWasVisited(true);
listAccessOrder.add(unvisitedNeighbour.getCarryingInfo());
System.out.println("Push into stack: " + unvisitedNeighbour);
}
// No, no this kind of neighbour
else {
System.out.println("Stack status just before pop: " + stack);
stack.pop();// topVertex(it's on the top of stack). When pop, we
// cannot find any neighbours which had NOT been
// visited(all neighbours of this vertex had already
// been visited)
}
}
return listAccessOrder;
}
public static List<Object> bfs(Graph g) {
List<Object> listAccessOrder = new ArrayList<Object>();
Queue<Vertex> queue = new LinkedList<Vertex>();
Vertex startVertex = pickFirstAccessVertex(g);
queue.offer(startVertex);
startVertex.setWasVisited(true);
listAccessOrder.add(startVertex.getCarryingInfo());
System.out.println("Offer for Queue: " + startVertex);
while (!queue.isEmpty()) {
System.out.println("Queue status just before poll: " + queue);
Vertex headVertex = queue.poll();// This had already been visited.
// When poll a vertex, this
// polled one had already been
// visited, but NONE of its
// neighbours
// except that one who introduce
// it into the queue has been
// visited
List<Vertex> listAllRemainingUnvisitedNeighbour = findAllRemainingUnVisitedNeighbour(
g, headVertex);
// Yes, we find all remaining vertices of this kind
if (listAllRemainingUnvisitedNeighbour.size() > 0) {
for (Iterator<Vertex> it = listAllRemainingUnvisitedNeighbour
.iterator(); it.hasNext();) {
Vertex oneNeighbour = (Vertex) it.next();
queue.offer(oneNeighbour);// When offer into queue, this one
// had already been visited, but
// its neighbours except
// <code>headVertex</code> have
// NOT been visited yet
oneNeighbour.setWasVisited(true);
listAccessOrder.add(oneNeighbour.getCarryingInfo());
System.out.println("Offer for Queue: " + oneNeighbour);
}
}
// No, no this kind of neighbour
else {
}
}
return listAccessOrder;
}
private static Vertex pickFirstAccessVertex(Graph g) {
return g.arrayVertices[0];
}
private static Vertex findOneUnVisitedNeighbour(Graph g, Vertex v) {
int row = -1;
for (int i = 0; i < g.nVerts; i++) {
if (g.arrayVertices[i] == v) {
row = i;
break;
}
}
if (row < 0) {
return null;// never happen
}
for (int column = 0; column < g.nVerts; column++) {
// not only neighbour of v, but also not been visited
if (g.adjMat[row][column] == 1
&& g.arrayVertices[column].isWasVisited() == false) {
return g.arrayVertices[column];
}
}
return null;
}
private static List<Vertex> findAllRemainingUnVisitedNeighbour(Graph g,
Vertex v) {
List<Vertex> listAllUnvisitedNeighbour = new ArrayList<Vertex>();
int row = -1;
for (int i = 0; i < g.nVerts; i++) {
if (g.arrayVertices[i] == v) {
row = i;
break;
}
}
if (row < 0) {
return listAllUnvisitedNeighbour;// never happen
}
for (int column = 0; column < g.nVerts; column++) {
// not only neighbour of v, but also not been visited
if (g.adjMat[row][column] == 1
&& g.arrayVertices[column].isWasVisited() == false) {
listAllUnvisitedNeighbour.add(g.arrayVertices[column]);
}
}
return listAllUnvisitedNeighbour;
}
}
Main.java
import java.util.List;
public class Main {
public static Graph createTestGraph() {
Graph g = new Graph();
g.addVertex("A");
g.addVertex("B");
g.addVertex("C");
g.addVertex("D");
g.addVertex("E");
g.addVertex("F");
g.addVertex("G");
g.addVertex("H");
g.addVertex("I");
g.addEdge(0, 1);// A--B
g.addEdge(0, 2);// A--C
g.addEdge(0, 3);// A--D
g.addEdge(0, 4);// A--E
g.addEdge(1, 5);// B--F
g.addEdge(5, 7);// F--H
g.addEdge(3, 6);// D--G
g.addEdge(6, 8);// G--I
return g;
}
public static void main(String[] args) {
System.out.println("Begin dfs search");
List dfsAccessOrder = SearchGraph.dfs(createTestGraph());
System.out.println("dfs: " + dfsAccessOrder);
System.out.println("Begin bfs search");
List bsfAccessOrder = SearchGraph.bfs(createTestGraph());
System.out.println("bfs: " + bsfAccessOrder);
}
}