有向无环图的java实现(使用矩阵特性开发)

    技术2022-07-11  71

    工作流如下图所示,要求每一个任务只执行一次,不重复执行,要求任务的所有前置任务必须完成才能往后执行,例如任务7必须在任务13,2,3三个任务完成之后才能执行,而任务13,2,3属于独立的任务,可以并发执行

     

    根据多线程求得出6个路线数据

    每个线程可以独立执行,所有线程相同的任务不能重复执行,当前任务必须在前置任务完成之后才能执行,

    路线:[1, 2, 7, 10, 12] 路线:[1, 13, 7, 10, 12] 路线:[1, 3, 7, 10, 12] 路线:[1, 4, 8, 10, 12] 路线:[1, 4, 9, 11, 12] 路线:[1, 5, 6, 9, 11, 12]

    路线不能出现回环,出现即死循环,需要提前排除

     

     

    实现代码如下(JDK1.8)

    数据结构类NetWork

    import java.util.*; /** * 图解网络数据结构 */ public class NetWork { //记录两份网络节点,使用空间换时间,提升反向查询效率 //网络初始化,x_k,y_k private Map<String, Map<String, String>> xMapMap; //网络初始化,y_k,x_k private Map<String, Map<String, String>> yMapMap; //回环路径 private List<String> loopbackList;//回环地址 //节点深度路径 private List<List<String>> deepPathList;//深度路径 private Map<String, String> jobMapStatus;//map任务状态 enum TYPE {X,Y} public NetWork() { xMapMap = new HashMap();//X点集 yMapMap = new HashMap();//Y点集 loopbackList = new LinkedList<>();//回环地址 deepPathList = new LinkedList<>();//深度路径 } /** * 初始化任务 */ public void initJob() { jobMapStatus = new HashMap<>(); Set<String> allPoint = getAllPoint(); allPoint.forEach(job -> jobMapStatus.put(job, "0"));//0,1 0表示未执行,1表示执行 } /** * 获取任务的转状态 * * @param job * @return */ public String getJobMapStatus(String job) { String status = jobMapStatus.get(job); return status; } /** * 更新任务的状态 * * @param job 任务名称 * @param status 任务状态 */ public void setJobMapStatus(String job, String status) { jobMapStatus.put(job, status); } public List<String> getLoopbackList() { return loopbackList; } public List<List<String>> getDeepPathList() { return deepPathList; } /** * 网络添加节点 * * @param xPoint x位 * @param yPoint y位 * @param distance 位移 */ public void addPoint(String xPoint, String yPoint, String distance) { if (!xMapMap.containsKey(xPoint)) {//记录x的索引 xMapMap.put(xPoint, new HashMap<>()); } xMapMap.get(xPoint).put(yPoint, distance); if (!yMapMap.containsKey(yPoint)) {//记录y的索引 yMapMap.put(yPoint, new HashMap<>()); } yMapMap.get(yPoint).put(xPoint, distance); } /** * 根据坐标获取某点 * * @param xPoint * @param yPoint * @return */ public String getPoint(String xPoint, String yPoint) { Map<String, String> linePoints = xMapMap.get(xPoint); String point = linePoints.get(yPoint); return point; } public String getPoint(String point1, String point2, TYPE type) { if (type == TYPE.X) { Map<String, String> linePoints = xMapMap.get(point1); String point = linePoints.get(point2); return point; } else { Map<String, String> linePoints = yMapMap.get(point1); String point = linePoints.get(point2); return point; } } /** * 获取X轴的一列数据 * * @param xPoint * @return */ public List<Map<String, String>> getLinePoint(String xPoint) { List<Map<String, String>> linePointList = new ArrayList<Map<String, String>>(); Map<String, String> linePoints = xMapMap.get(xPoint); if (linePoints != null) { for (Map.Entry<String, String> pointUnit : linePoints.entrySet()) { Map<String, String> pointMap = new HashMap<String, String>(); pointMap.put("X", xPoint); pointMap.put("Y", pointUnit.getKey()); pointMap.put("D", pointUnit.getValue()); linePointList.add(pointMap); } } return linePointList; } /** * 根据类型获取某轴的一列数据 * * @param point 索引点 * @param type 类型 * @return */ public List<Map<String, String>> getLinePoint(String point, TYPE type) { List<Map<String, String>> linePointList = new ArrayList<Map<String, String>>(); if (type == TYPE.X) { Map<String, String> linePoints = xMapMap.get(point); if (linePoints != null) { for (Map.Entry<String, String> pointUnit : linePoints.entrySet()) { Map<String, String> pointMap = new HashMap<String, String>(); pointMap.put("X", point); pointMap.put("Y", pointUnit.getKey()); pointMap.put("D", pointUnit.getValue()); linePointList.add(pointMap); } } } else { Map<String, String> linePoints = yMapMap.get(point); if (linePoints != null) { for (Map.Entry<String, String> pointUnit : linePoints.entrySet()) { Map<String, String> pointMap = new HashMap<String, String>(); pointMap.put("X", pointUnit.getKey()); pointMap.put("Y", point); pointMap.put("D", pointUnit.getValue()); linePointList.add(pointMap); } } } return linePointList; } /** * @param netWork 网络节点 * @param startPoint 起始节点 * @param pathList 当前任务的路径 */ public void recursive(NetWork netWork, String startPoint, ArrayList<String> pathList) { if (pathList.contains(startPoint)) {netWork.getLoopbackList().add(pathList.toString() + "->" + startPoint);return;} pathList.add(startPoint); List<Map<String, String>> linePoint = netWork.getLinePoint(startPoint, NetWork.TYPE.X); if (linePoint.size() == 0) { ArrayList<String> descList = new ArrayList<>(pathList.size()); pathList.forEach(path -> descList.add(path)); netWork.getDeepPathList().add(descList); } for (Map<String, String> map : linePoint) {recursive(netWork, map.get("Y"), pathList);} pathList.remove(startPoint); } /** * 获取所有的点,合并key * * @return */ public Set<String> getAllPoint() { Set<String> allSet1 = xMapMap.keySet(); Set<String> allSet2 = yMapMap.keySet(); Set<String> allSet = new HashSet<>(); allSet.addAll(allSet1); allSet.addAll(allSet2); return allSet; } /** * 显示路径 */ public void show() { int placeholder = 3; String placeholderSrting = ""; for (int i = 0; i < placeholder; i++) {placeholderSrting = placeholderSrting + "-";} Set<String> allSet = getAllPoint();//获取所有的点,用于遍历 System.out.print(String.format("%-" + placeholder + "s", "")); System.out.print(" "); for (String x : allSet) { System.out.print(String.format("%-" + placeholder + "s", x)); } System.out.println(); System.out.print(String.format("%-" + placeholder + "s", "X\\Y")); System.out.print(" "); for (String ignored : allSet) {System.out.print(placeholderSrting);} System.out.println(); for (String x : allSet) { System.out.print(String.format("%-" + placeholder + "s|", x)); for (String y : allSet) { Map<String, String> linePoints = xMapMap.get(x); String point = "0"; if (linePoints != null && linePoints.get(y) != null) { point = linePoints.get(y); } System.out.print(String.format("%-" + placeholder + "s", point)); } System.out.println(); } } }

     

    测试类TestMain

    import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; /** * 网络计算 */ public class TestMain { public static ConcurrentMap<String, List<String>> println = new ConcurrentHashMap<>(); public static List<String> strings = new ArrayList<>(); public static void main(String[] args) throws InterruptedException { NetWork netWork = new NetWork(); netWork.addPoint("1", "2", "1"); netWork.addPoint("1", "3", "1"); netWork.addPoint("1", "4", "1"); netWork.addPoint("1", "5", "1"); netWork.addPoint("1", "13", "1"); netWork.addPoint("2", "7", "1"); netWork.addPoint("3", "7", "1"); netWork.addPoint("13", "7", "1"); netWork.addPoint("4", "8", "1"); netWork.addPoint("4", "9", "1"); netWork.addPoint("5", "6", "1"); netWork.addPoint("6", "9", "1"); netWork.addPoint("7", "10", "1"); netWork.addPoint("8", "10", "1"); netWork.addPoint("9", "11", "1"); netWork.addPoint("10", "12", "1"); netWork.addPoint("11", "12", "1"); netWork.initJob();//初始化所有节点任务 //netWork.addPoint("6", "1", "1");netWork.addPoint("4", "6", "1");//回环的两条数据 netWork.show(); //获取起点,如图起点为1 String startPoint = "1"; netWork.recursive(netWork, startPoint, new ArrayList<>()); //递归计算所有节点的路径 if (netWork.getLoopbackList().size() != 0) { System.out.println("出现回环地址,回环地址的路径为:" + netWork.getLoopbackList()); return; } //开始计算任务 for (List<String> pathJobList : netWork.getDeepPathList()) { new Thread(() -> { System.out.println("路线:" + pathJobList); for (int i = 0; i < pathJobList.size(); i++) { String job = pathJobList.get(i); List<String> linePoint = new ArrayList<>();//获取任务前置条件 netWork.getLinePoint(job, NetWork.TYPE.Y).forEach(jobLine -> linePoint.add(jobLine.get("X"))); /*System.out.println("任务" + job + "的前置条件:" + linePoint);*/ execJob(job, linePoint, netWork);//执行任务 } }).start(); } Thread.sleep(1000);//这里使用的休眠进行下一次判断,也可以使用锁同步数据,使用锁实现较为复杂 for (Map.Entry<String, List<String>> entry : println.entrySet()) { System.out.println(entry); } System.out.println("执行顺序:" + strings); } /** * 执行任务 * * @param job */ private static void execJob(String job, List<String> linePoint, NetWork netWork) { List<String> tmp = new ArrayList<>(); while (true) { for (String precondition : linePoint) { String jobMapStatus; synchronized (String.class) {jobMapStatus = netWork.getJobMapStatus(precondition);} if (!"1".equals(jobMapStatus)) {tmp.add(precondition);}//未执行 } if (tmp.size() == 0) {break;} linePoint.clear(); tmp.forEach(jobTmp -> linePoint.add(jobTmp)); tmp.clear(); /*此处可以随机数休眠模拟任务执行所需的时间*/ } String jobMapStatus; Boolean status = false;//是否需要执行任务 synchronized (String.class) { jobMapStatus = netWork.getJobMapStatus(job); if ("1".equals(jobMapStatus)) {return;}//任务已经完成 if ("0".equals(jobMapStatus)) {netWork.setJobMapStatus(job, "-1");status = true;}//立即执行 } if (status) { synchronized (String.class) { if (!println.containsKey(Thread.currentThread().getName())) { println.put(Thread.currentThread().getName(), new ArrayList<>()); } println.get(Thread.currentThread().getName()).add(job);strings.add(job); netWork.setJobMapStatus(job, "1"); } } } }

    测试结果如下

     

     

    实现原理是使用矩阵,X轴表示起始点,Y轴表示结束点,起始点与结束点对应的值为1 即表示起始点与结束点之间是一条通线,如果值为0 即表示这两点之间不通

    根据矩阵原理开发

        起始点对应的一行中所有值为1的结束点为起始点可到达的结束点

        结束点对应的一列中所有值为1的起始点是结束点所表示任务的前置任务

     

    所以数据结构NetWork类中已经封装好了通过x,y坐标获取一个值和通过x或者通过y获取一行或者一列数据的方法

     

     

    Processed: 0.011, SQL: 9