mes-lqqt/ktg-common/src/main/java/com/ktg/common/utils/MapCircleUtils.java

147 lines
3.7 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.ktg.common.utils;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* @author yinjinlu
* @description 物料BOM环形依赖关系有向图检测
* @date 2024/12/18
*/
@Service
public class MapCircleUtils {
private Map<Long,List<Long>> adj; // 邻接表
private MapCircleUtils() {
this.adj = new HashMap<>();
}
// 静态工厂方法,用于创建实例
public static MapCircleUtils createInstance() {
return new MapCircleUtils();
}
public void clear() {
adj.clear();
}
/**
* 向图中添加一条从顶点v到顶点w的边无向图则双向添加
* @param v 起点
* @param w 终点
*/
public void addEdge(Long v, Long w) {
adj.putIfAbsent(v, new ArrayList<>());
adj.putIfAbsent(w, new ArrayList<>());
adj.get(v).add(w);
// adj.get(w).add(v); // 对于无向图,添加反向边
}
/**
* 向图中添加一个节点(如果节点已存在,则不执行任何操作)
* @param vertex 要添加的节点
*/
public void addVertex(Long vertex) {
adj.putIfAbsent(vertex, new ArrayList<>());
}
/**
* 返回图中的顶点数量
* @return
*/
public int getVertices() {
return adj.size();
}
/**
* 检测从顶点 v 出发是否存在环
* @param v
* @param visited
* @param onStack
* @return
*/
private boolean isCircleUtil(Long v, boolean[] visited, boolean[] onStack) {
if (visited[v.intValue()]) {
return true; // 已经访问过,说明有环
}
if (onStack[v.intValue()]) {
return false; // 已访问过且不在递归栈中
}
visited[v.intValue()] = true;
onStack[v.intValue()] = true;
for (Long w : adj.getOrDefault(v, Collections.emptyList())) {
if (isCircleUtil(w, visited, onStack)) {
return true;
}
}
onStack[v.intValue()] = false;
return false;
}
/**
* 图中顶点索引的最大值
* @return
*/
private Long getMaxVertextIndex(){
return adj.isEmpty() ? -1L : Collections.max(adj.keySet());
}
/**
* 检测图中是否存在环
* @return
*/
public boolean hasCircle() {
Long max = getMaxVertextIndex();
boolean[] visited = new boolean[(int) (max + 1)];
boolean[] onStack = new boolean[(int) (max + 1)];
for ( Long vertext: adj.keySet()) {
if (!visited[vertext.intValue()] && isCircleUtil(vertext, visited, onStack)) {
return true;
}
}
return false;
}
public boolean hasCycle() {
Set<Long> visited = new HashSet<>();
Set<Long> inPath = new HashSet<>();
for (Long node : adj.keySet()) {
if (!visited.contains(node)) {
if (dfs(adj, node, visited, inPath)) {
return true;
}
}
}
return false;
}
private boolean dfs(Map<Long, List<Long>> graph, Long node, Set<Long> visited, Set<Long> inPath) {
visited.add(node);
inPath.add(node);
List<Long> neighbors = graph.get(node);
if (neighbors != null) {
for (Long neighbor : neighbors) {
if (!visited.contains(neighbor)) {
if (dfs(graph, neighbor, visited, inPath)) {
return true;
}
} else if (inPath.contains(neighbor)) {
return true;
}
}
}
inPath.remove(node); // 回溯时移除当前节点
return false;
}
}