如果所示,一幅图包含了若干个顶点和若干条边,每条边含有权重。
废话不说,下面讲讲如何实现一幅图吧
由图可知,一幅图由两部分组成,顶点和边,而边依赖于顶点,每条边包含了两个顶点和权重,由此可得到,每个顶点可抽象出一个类,每条边可抽象一个类。
顶点:
static class Vertex<V, E> {
V value;
//以当前顶点为起点的边的集合
Set<Edge<V, E>> inEdges = new HashSet<>();
//以当前顶点为终点的边的集合
Set<Edge<V, E>> outEdges = new HashSet<>();
public Vertex(V value) {
this.value = value;
}
@Override
public String toString() {
return value == null ? "null" : value.toString();
}
@Override
public boolean equals(Object o) {
Vertex<?, ?> vertex = (Vertex<?, ?>) o;
return Objects.equals(value, vertex.value);
}
@Override
public int hashCode() {
return Objects.hash(value);
}
}
边:
static class Edge<V, E>{
Vertex<V, E> from;
Vertex<V, E> to;
E weight;
@Override
public String toString() {
return "Edge{" +
"from=" + from.toString() +
", to=" + to.toString() +
", weight=" + weight +
'}';
}
public Edge(Vertex<V, E> from, Vertex<V, E> to) {
this.from = from;
this.to = to;
}
public Edge(Vertex<V, E> from, Vertex<V, E> to, E weight) {
this.from = from;
this.to = to;
this.weight = weight;
}
@Override
public boolean equals(Object o) {
Edge<?, ?> edge = (Edge<?, ?>) o;
return Objects.equals(from, edge.from) && Objects.equals(to, edge.to);
}
@Override
public int hashCode() {
return Objects.hash(from, to);
}
每个图会有CRUD,所以暂时定义几个接口:
int edgesSize();//获取边的数量
int verticesSize(); //获取顶点的数量
void addVertex(V value); //添加顶点
void addEdge(V from, V to);//添加边
void addEdge(V from, V to, E weight); //添加边和权重
void removeVertex(V v); //删除顶点
void removeEdge(V from, V to); //删除边
void print(); //打印图的信息
实现:定义类实现这几个方法,实现类中包含这两个属性,
//key:顶点的值 value:顶点
private final Map<V, Vertex<V, E>> vertices = new HashMap<>();
//边的信息
private final Set<Edge<V, E>> edges = new HashSet<>();
打印图的信息:
@Override
public void print() {
System.out.println("---------------------------------------------------------------------");
vertices.forEach((k, v) -> {
System.out.print(k);
System.out.println(" in: " + v.inEdges);
System.out.println(" out: " + v.outEdges);
});
edges.forEach(System.out::println);
System.out.println("---------------------------------------------------------------------");
}
添加顶点:
只需要往图的顶点集合中添加就行
@Override
public void addVertex(V value) {
vertices.computeIfAbsent(value, k -> new Vertex<>(value));
}
添加边(无权重):
@Override
public void addEdge(V from, V to) {
addEdge(from, to, null);
}
添加边:
先看看顶点是否存在,存在就拿出来,不存在就新添加顶点。
将这条边加入到以该fromVertex为起点的边的集合中
将这条边加入到以该toVertex为终点的边的集合中
@Override
public void addEdge(V from, V to, E weight) {
Vertex<V, E> fromVertex = vertices.computeIfAbsent(from, k -> new Vertex<>(from));
Vertex<V, E> toVertex = vertices.computeIfAbsent(to, k -> new Vertex<>(to));
Edge<V, E> edge = new Edge<>(fromVertex, toVertex, weight);
if (fromVertex.outEdges.remove(edge)) {
toVertex.inEdges.remove(edge);
edges.remove(edge);
}
fromVertex.outEdges.add(edge);
toVertex.inEdges.add(edge);
edges.add(edge);
}
删除顶点:
通过当前 顶点获取到连接到该顶点的所有边,根据该边获取到另一个端点,将该边从另一个端点的集合中删除即可
@Override
public void removeVertex(V v) {
Vertex<V, E> vertex = vertices.remove(v);
if (vertex != null) {
Iterator<Edge<V, E>> outIterator = vertex.outEdges.iterator();
while (outIterator.hasNext()) {
Edge<V, E> edge = outIterator.next();
edge.to.inEdges.remove(edge);
outIterator.remove();
edges.remove(edge);
}
Iterator<Edge<V, E>> inIterator = vertex.inEdges.iterator();
while (inIterator.hasNext()) {
Edge<V, E> edge = inIterator.next();
edge.from.outEdges.remove(edge);
inIterator.remove();
edges.remove(edge);
}
}
}
删除边:
删除一条边,思路:找到这条边对应的两个顶点,对于起点来说,将这条边从以这个顶点为起点的边的集合中删除即可;对于这条的终点,将这条边从以这个顶点为终点的边的集合中删除即可。
@Override
public void removeEdge(V from, V to) {
Vertex<V, E> fromVertex = vertices.get(from);
if (fromVertex == null) {
return;
}
Vertex<V, E> toVertex = vertices.get(to);
if (toVertex == null) {
return;
}
Edge<V, E> edge = new Edge<>(fromVertex, toVertex);
if (fromVertex.outEdges.remove(edge)) {
toVertex.inEdges.remove(edge);
edges.remove(edge);
}
}
获取顶点的数量:
@Override
public int verticesSize() {
return vertices.size();
}
获取边的数量:
@Override
public int edgesSize() {
return 0;
}