有向無環圖的java實現(使用矩陣特性開發)

工作流如下圖所示,要求每一個任務只執行一次,不重複執行,要求任務的所有前置任務必須完成才能往後執行,例如任務7必須在任務13,2,3三個任務完成之後才能執行,而任務13,2,3屬於獨立的任務,可以併發執行

 

根據多線程要求得出5個路線數據

每個線程可以獨立執行,所有線程相同的任務不能重複執行,當前任務必須在前置任務完成之後才能執行,

路線:[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();
//            try {Thread.sleep(100);} catch (InterruptedException e) { e.printStackTrace();}
        }
        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獲取一行或者一列數據的方法

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章