最近在学《算法 第四版》,刚学完无向图的深度优先搜索和广度优先搜索,并参照示例,写了支持泛型的Graph类,并同样写了支持泛型的搜索类,仅供参考。
package org.tafia.graph;
import java.util.Set;
/**
* 顶点为类型T的图
*
* @author Dason
* @date 2016年10月12日
*
*/
public interface Graph<T> {
/**
* 所有顶点
* @return 顶点的集合
*/
Set<T> vertex();
/**
* 边的数量
* @return 边的数量
*/
int edge();
/**
* 连接顶点v1和v2
* @param v1 顶点1
* @param v2 顶点2
*/
void join(T v1, T v2);
/**
* 与顶点v相连的顶点
* @param vertex
* @return 顶点的集合
*/
Set<T> adjoin(T v);
}
package org.tafia.graph;
import java.util.Set;
public class AbstractGraph<T> implements Graph<T> {
@Override
public Set<T> vertex() {
throw new UnsupportedOperationException();
}
@Override
public int edge() {
throw new UnsupportedOperationException();
}
@Override
public void join(T v1, T v2) {
throw new UnsupportedOperationException();
}
@Override
public Set<T> adjoin(T v) {
throw new UnsupportedOperationException();
}
}
package org.tafia.graph;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class HashUndirectedGraph<T> extends AbstractGraph<T> {
private Map<T, Set<T>> adjoinMap;
private int numOfEdges = 0;
/**
* 创建指定顶点的无向图
* @param vertexList 顶点集合
*/
public HashUndirectedGraph(Set<T> vertexList) {
adjoinMap = new HashMap<>(vertexList.size());
for (T v : vertexList) {
adjoinMap.put(v, new HashSet<>());
}
}
@Override
public Set<T> vertex() {
Set<T> set = new HashSet<>();
for (T v : adjoinMap.keySet()) {
set.addAll(adjoinMap.get(v));
}
return set;
}
@Override
public int edge() {
return numOfEdges;
}
@Override
public void join(T v1, T v2) {
if (!adjoinMap.containsKey(v1) || !adjoinMap.containsKey(v2)){
return;
}
adjoinMap.get(v1).add(v2);
adjoinMap.get(v2).add(v1);
numOfEdges++;
}
@Override
public Set<T> adjoin(T v) {
return adjoinMap.get(v);
}
}
package org.tafia.graph;
import java.util.List;
public interface GraphSearch<T> {
/**
* 是否包含到顶点v的路径
* @param v 顶点
* @return 如果包含返回true,否则返回false
*/
boolean hasPathTo(T v);
/**
* 返回到顶点v的路径集合
* @param v 顶点
* @return 路径集合
*/
List<T> pathTo(T v);
}
package org.tafia.graph;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
public class DeepFirstGraphSearch<T> implements GraphSearch<T> {
private Map<T, Boolean> marked = new HashMap<>();
private Map<T, T> pathTo = new HashMap<>();
private T vertex;
/**
* 构造器
* @param graph 图
* @param vertex 操作的顶点
*/
public DeepFirstGraphSearch(Graph<T> graph, T vertex) {
this.vertex = vertex;
for (T v : graph.vertex()) {
marked.put(v, Boolean.FALSE);
}
dfs(graph, vertex);
}
private void dfs(Graph<T> graph, T vertex) {
marked.put(vertex, Boolean.TRUE);
for (T v : graph.adjoin(vertex)) {
if (!marked.get(v)) {
pathTo.put(v, vertex);
dfs(graph, v);
}
}
}
@Override
public boolean hasPathTo(T v) {
return marked.get(v);
}
@Override
public List<T> pathTo(T v) {
Stack<T> stack = new Stack<>();
for (; v != vertex; v = pathTo.get(v)) {
stack.push(v);
}
List<T> list = new ArrayList<>(stack.size() + 1);
list.add(vertex);
while (!stack.isEmpty()) {
list.add(stack.pop());
}
return list;
}
public static void main(String[] args) {
Set<String> cities = new HashSet<>();
cities.add("北京");
cities.add("天津");
cities.add("河南");
cities.add("河北");
cities.add("山东");
cities.add("山西");
Graph<String> graph = new HashUndirectedGraph<>(cities);
graph.join("北京", "天津");
graph.join("北京", "河北");
graph.join("河北", "山西");
graph.join("河北", "天津");
graph.join("山西", "山东");
graph.join("天津", "山东");
graph.join("天津", "河南");
String from = "山西";
GraphSearch<String> gs = new DeepFirstGraphSearch<>(graph, from);
for (String to : graph.vertex()) {
boolean hasPathTo = gs.hasPathTo(to);
System.out.println(hasPathTo ? gs.pathTo(to) : from+"×"+to);
}
}
}
package org.tafia.graph;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.Stack;
import java.util.concurrent.LinkedBlockingQueue;
public class BreadthFirstGraphSearch<T> implements GraphSearch<T> {
private Map<T, Boolean> marked = new HashMap<>();
private Map<T, T> pathTo = new HashMap<>();
private T vertex;
/**
* 构造器
* @param graph 图
* @param vertex 操作的顶点
*/
public BreadthFirstGraphSearch(Graph<T> graph, T vertex) {
this.vertex = vertex;
for (T v : graph.vertex()) {
marked.put(v, Boolean.FALSE);
}
bfs(graph, vertex);
}
private void bfs(Graph<T> graph, T vertex) {
marked.put(vertex, Boolean.TRUE);
Queue<T> queue = new LinkedBlockingQueue<>();
queue.offer(vertex);
while (!queue.isEmpty()) {
vertex = queue.poll();
for (T v : graph.adjoin(vertex)) {
if (!marked.get(v)) {
marked.put(v, Boolean.TRUE);
pathTo.put(v, vertex);
queue.offer(v);
}
}
}
}
@Override
public boolean hasPathTo(T v) {
return marked.get(v);
}
@Override
public List<T> pathTo(T v) {
Stack<T> stack = new Stack<>();
for (; v != vertex; v = pathTo.get(v)) {
stack.push(v);
}
List<T> list = new ArrayList<>(stack.size() + 1);
list.add(vertex);
while (!stack.isEmpty()) {
list.add(stack.pop());
}
return list;
}
public static void main(String[] args) {
Set<String> cities = new HashSet<>();
cities.add("北京");
cities.add("天津");
cities.add("河南");
cities.add("河北");
cities.add("山东");
cities.add("山西");
Graph<String> graph = new HashUndirectedGraph<>(cities);
graph.join("北京", "天津");
graph.join("北京", "河北");
graph.join("河北", "山西");
graph.join("河北", "天津");
graph.join("山西", "山东");
graph.join("天津", "山东");
graph.join("天津", "河南");
String from = "北京";
GraphSearch<String> gs = new BreadthFirstGraphSearch<>(graph, from);
for (String to : graph.vertex()) {
boolean hasPathTo = gs.hasPathTo(to);
System.out.println(hasPathTo ? gs.pathTo(to) : from+"×"+to);
}
}
}