图-Java实现

217 阅读2分钟

需求:

有向图 如何用java代码表示以上的有向带权值的图,实现如下接口:

  1. 查看顶点数
  2. 查看边数量
  3. 新增顶点
  4. 删除顶点
  5. 新增边
  6. 删除边

顶点的定义

    /**
	 * 顶点的定义
	 */
	private 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 boolean equals(Object obj) {
			Vertex<V, E> vertex = (Vertex<V, E>) obj;
			return Objects.equals(value, vertex.value);
		}

		@Override
		public int hashCode() {
			return value == null ? 0 : value.hashCode();
		}
	}

边的定义

/**
	 * 边的定义
	 */
	private static class Edge<V, E> {
		/**
		 * 边的起点
		 */
		Vertex<V, E> from;
		/**
		 * 边的终点
		 */
		Vertex<V, E> to;
		/**
		 * 边的权值
		 */
		E weight;

		/**
		 * 只要两条边的起点和终点相等,就认为这两条边相等
		 */
		@Override
		public boolean equals(Object obj) {
			Edge<V, E> edge = (Edge<V, E>) obj;
			return from.equals(edge.from) && to.equals(edge.to);
		}

		@Override
		public int hashCode() {
			return from.hashCode() * 31 + to.hashCode();
		}
	}

完整代码

/**
 * 图-java实现
 *
 * @author zhangj
 * @date 2020/10/1
 */
public class Graph<V, E> {
	/**
	 * 所有的顶点,一个V对应一个顶点
	 */
	private Map<V, Vertex<V, E>> vertices = new HashMap<>();
	/**
	 * 所有的边
	 */
	private Set<Edge<V, E>> edges = new HashSet<>();

	/**
	 * 获取图顶点的数量
	 */
	public int verticesSize() {
		return vertices.size();
	}

	/**
	 * 获取图边的数量
	 */
	public int edgesSize() {
		return edges.size();
	}

	/**
	 * 新增顶点
	 */
	public void addVertex(V v) {
		//判断顶点是否存在,只有不存在才新增
		if (vertices.containsKey(v)) {
			return;
		}
		vertices.put(v, new Vertex<>(v));
	}

	/**
	 * 删除顶点
	 */
	public void removeVertex(V v) {
		//先从集合里删除
		Vertex<V, E> vertex = vertices.remove(v);
		if (vertex == null) {
			return;
		}

		//删除这个顶点出度的边
		for (Iterator<Edge<V, E>> iterator = vertex.outEdges.iterator(); iterator.hasNext(); ) {
			Edge<V, E> edge = iterator.next();
			edge.to.inEdges.remove(edge);
			//从vertex.outEdges里删除
			iterator.remove();
			//从集合里删除
			edges.remove(edge);
		}

		//删除这个顶点入度的边
		for (Iterator<Edge<V, E>> iterator = vertex.inEdges.iterator(); iterator.hasNext(); ) {
			Edge<V, E> edge = iterator.next();
			edge.from.outEdges.remove(edge);
			//从vertex.outEdges里删除
			iterator.remove();
			//从集合里删除
			edges.remove(edge);
		}
	}

	/**
	 * 添加边,不带权值
	 */
	public void addEdge(V fromV, V toV) {
		addEdge(fromV, toV, null);
	}

	/**
	 * 添加边,带权值
	 */
	public void addEdge(V fromV, V toV, E weight) {
		//查看起点是否存在,不存在新增
		Vertex<V, E> fromVertex = vertices.get(fromV);
		if (fromVertex == null) {
			//新增一个节点
			fromVertex = new Vertex<>(fromV);
			vertices.put(fromV, fromVertex);
		}
		//查看终点是否存在,不存在新增
		Vertex<V, E> toVertex = vertices.get(toV);
		if (toVertex == null) {
			//新增一个节点
			toVertex = new Vertex<>(toV);
			vertices.put(toV, toVertex);
		}

		//构造一条边
		Edge<V, E> edge = new Edge<>(fromVertex, toVertex);
		edge.weight = weight;

		//删除边
		if (fromVertex.outEdges.remove(edge)) {
			toVertex.inEdges.remove(edge);
			edges.remove(edge);
		}

		//新增边
		fromVertex.outEdges.add(edge);
		toVertex.inEdges.add(edge);
		edges.add(edge);
	}

	/**
	 * 删除边
	 */
	public void removeEdge(V formV, V toV) {
		//判断起点是否存在,不存在直接退出
		Vertex<V, E> fromVertex = vertices.get(formV);
		if (fromVertex == null) {
			return;
		}

		//判断终点是否存在,不存在直接退出
		Vertex<V, E> toVertex = vertices.get(toV);
		if (toVertex == null) {
			return;
		}

		//构造一条边
		Edge<V, E> edge = new Edge<>(fromVertex, toVertex);

		//删除边
		if (fromVertex.outEdges.remove(edge)) {
			toVertex.inEdges.remove(edge);
			edges.remove(edge);
		}
	}

	/**
	 * 顶点的定义
	 */
	private 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 boolean equals(Object obj) {
			Vertex<V, E> vertex = (Vertex<V, E>) obj;
			return Objects.equals(value, vertex.value);
		}

		@Override
		public int hashCode() {
			return value == null ? 0 : value.hashCode();
		}

		@Override
		public String toString() {
			return value == null ? "null" : value.toString();
		}
	}

	/**
	 * 边的定义
	 */
	private static class Edge<V, E> {
		/**
		 * 边的起点
		 */
		Vertex<V, E> from;
		/**
		 * 边的终点
		 */
		Vertex<V, E> to;
		/**
		 * 边的权值
		 */
		E weight;

		/**
		 * 构造函数
		 *
		 * @param from 起点
		 * @param to   终点
		 */
		public Edge(Vertex<V, E> from, Vertex<V, E> to) {
			this.from = from;
			this.to = to;
		}

		/**
		 * 只要两条边的起点和终点相等,就认为这两条边相等
		 */
		@Override
		public boolean equals(Object obj) {
			Edge<V, E> edge = (Edge<V, E>) obj;
			return from.equals(edge.from) && to.equals(edge.to);
		}

		@Override
		public int hashCode() {
			return from.hashCode() * 31 + to.hashCode();
		}

		@Override
		public String toString() {
			return "Edge [from=" + from + ", to=" + to + ", weight=" + weight + "]";
		}
	}

	public void print() {
		System.out.println("[顶点]-------------------");
		vertices.forEach((V v, Vertex<V, E> vertex) -> {
			System.out.println(v);
			System.out.println("out-----------");
			System.out.println(vertex.outEdges);
			System.out.println("in-----------");
			System.out.println(vertex.inEdges);
		});

		System.out.println("[边]-------------------");
		edges.forEach((Edge<V, E> edge) -> {
			System.out.println(edge);
		});
	}
}

测试

public static void main(String[] args) {
		Graph<String, Integer> graph = new Graph<>();
		graph.addEdge("V1", "V0", 9);
		graph.addEdge("V1", "V2", 3);
		graph.addEdge("V2", "V0", 2);
		graph.addEdge("V2", "V3", 5);
		graph.addEdge("V3", "V4", 1);
		graph.addEdge("V0", "V4", 6);

		graph.print();
	}

运行结果:

[顶点]-------------------
V0
out-----------
[Edge [from=V0, to=V4, weight=6]]
in-----------
[Edge [from=V1, to=V0, weight=9], Edge [from=V2, to=V0, weight=2]]
V1
out-----------
[Edge [from=V1, to=V2, weight=3], Edge [from=V1, to=V0, weight=9]]
in-----------
[]
V2
out-----------
[Edge [from=V2, to=V3, weight=5], Edge [from=V2, to=V0, weight=2]]
in-----------
[Edge [from=V1, to=V2, weight=3]]
V3
out-----------
[Edge [from=V3, to=V4, weight=1]]
in-----------
[Edge [from=V2, to=V3, weight=5]]
V4
out-----------
[]
in-----------
[Edge [from=V3, to=V4, weight=1], Edge [from=V0, to=V4, weight=6]]
[边]-------------------
Edge [from=V1, to=V2, weight=3]
Edge [from=V2, to=V3, weight=5]
Edge [from=V3, to=V4, weight=1]
Edge [from=V0, to=V4, weight=6]
Edge [from=V1, to=V0, weight=9]
Edge [from=V2, to=V0, weight=2]