DAG項目

 

目錄

一、Graph接口

二、Path

三、SparseGraph 

四、Tracer

五、Tree

 Main函數


一、Graph接口

package IMUHERO.DAG;
// 圖的接口

public interface Graph {
    /**
     *
     * @return
     */
    int V();

    /**
     *
     * @return
     */
    int E();

//    /**
//     *
//     * @param v
//     * @param w
//     */
//    void addEdge(int v, int w);

    /**
     *
     * @param v
     * @param w
     * @return
     */
    boolean hasEdge(int v, int w);

    /**
     *
     */
    void showTrace();

    /**
     *
     * @param v
     * @return
     */
    Iterable<Integer> adj(int v);

    /**
     * @param spanId
     * @return
     */
    public int findIndex(String spanId);
}

二、Path

package IMUHERO.DAG;
import java.util.ArrayList;
import java.util.Stack;
import java.util.Vector;

public class Path {

    private SparseGraph graph;   // 圖的引用
    private int start;     // 起始點
    private boolean[] visited;  // 記錄dfs的過程中節點是否被訪問
    private int[] from;         // 記錄路徑, from[i]表示查找的路徑上i的上一個節點

    /**
     * 構造函數, 尋路算法, 尋找圖graph從start點到其他點的路徑
     * @param graph
     * @param start
     */
    public Path(SparseGraph graph, int start){
        // 算法初始化
        this.graph = graph;
        this.start = start;
        assert start >= 0 && start < this.graph.V();
        visited = new boolean[this.graph.V()];       //JAVA底層默認爲false
        from = new int[this.graph.V()];              //記錄當前下標被誰調用
        for(int i = 0; i < this.graph.V() ; i ++ ){
            from[i] = -1;   //默認都沒有被調用,調用下標設爲-1
        }
        // 尋路算法
        dfs(start);
    }

    public Path(SparseGraph graph ,String spanId){
        this(graph,graph.findIndex(spanId));    //根據spanId查找到其在list中存儲的下標,並且組織路徑
    }

    // 圖的深度優先遍歷
    private void dfs( int v ){
        visited[v] = true;
        for( int i : graph.adj(v) )
            if( !visited[i] ){
                from[i] = v;
                dfs(i);
            }
    }

    // 輔助函數:查詢從s點到w點是否有路徑
    boolean hasPath(int w){
        assert w >= 0 && w < graph.V();
        return visited[w];
    }

    // 輔助函數:查詢從s點到w點的路徑, 存放在vec中
    Vector<Integer> path(int w){
        assert hasPath(w) ;
        Stack<Integer> s = new Stack<Integer>();
        // 通過from數組逆向查找到從s到w的路徑, 存放到棧中
        int p = w;
        while( p != -1 ){
            s.push(p);
            p = from[p];
        }
        // 從棧中依次取出元素, 獲得順序的從s到w的路徑
        Vector<Integer> res = new Vector<Integer>();
        while( !s.empty() )
            res.add( s.pop() );
        return res;
    }

    // 打印出從s點到w點的路徑
    void showPath(int w){
        assert hasPath(w) ;
        Vector<Integer> vec = path(w);
        for( int i = 0 ; i < vec.size() ; i ++ ){
            System.out.print(vec.elementAt(i));
            if( i == vec.size() - 1 )
                System.out.println();
            else
                System.out.print(" -> ");
        }
    }

    //打印從start節點開始的所有路徑
    public ArrayList<ArrayList<Integer>> showAllPath(){
        ArrayList<Integer> path = new ArrayList<>();
        ArrayList<ArrayList<Integer>> allPath = new ArrayList<>();
        showAllPath(start,path,allPath);
        return allPath;
    }
    //遞歸回溯,添加路徑信息
    private void showAllPath(int index, ArrayList<Integer> path , ArrayList<ArrayList<Integer>> allPath){
        path.add(index);
        //如果是最後一個節點
        if (graph.isLast(index)){
            ArrayList<Integer> copyPath = (ArrayList<Integer>)path.clone();
            allPath.add(copyPath);
            return;
        }
        for (int a:graph.adj(index)){
            showAllPath(a,path,allPath);
            path.remove(path.size()-1);
        }
        return;
    }

//    // 測試尋路算法
//    public static void main(String[] args) {
//
//        String filename = "testG.txt";
//        SparseGraph g = new SparseGraph(7, false);
//        ReadGraph readGraph = new ReadGraph(g, filename);
//        g.show();
//        System.out.println();
//
//        Path path = new Path(g,0);
//        System.out.println("Path from 0 to 6 : ");
//        path.showPath(6);
//    }
}

三、SparseGraph 

/**
 * 功能:構建DAG
 * 前提:默認傳輸進來一個ArrayList<Tracer>list,裏面已經將JSON數據封裝成java類
 */
package IMUHERO.DAG;
import java.util.ArrayList;
import java.util.Vector;

// 稀疏圖 - 鄰接表
public class SparseGraph implements Graph {

    private int n;  // 節點數
    private int m;  // 邊數
    private Vector<Integer>[] g;    // 圖的具體數據
    private ArrayList<Tracer>list;  //裏面每個位置存儲了一個Tracer,包含各種id

    // 構造函數
    public SparseGraph(ArrayList<Tracer> list){
        assert n >= 0;
        this.n = list.size();   //節點數==傳輸進來的list的大小
        this.m = 0;             // 初始化沒有任何邊
        this.list = list;

        // g初始化爲n個空的vector, 表示每一個g[i]都爲空, 即沒有任何邊
        g = (Vector<Integer>[])new Vector[n];
        for(int i = 0 ; i < n ; i ++)
            g[i] = new Vector<Integer>();

        //根據list的數據,生成圖(使用遍歷的方式,時間效率有待改善)
        for (int i=0;i<n;i++){
            addEdge(i); //對下標爲i的trace連接邊
        }
    }

    public int V(){ return n;}      // 返回節點個數
    public int E(){ return m;}      // 返回邊的個數

    // 向圖中添加一個邊
    public void addEdge( int end ){
        assert end>0&&end<n;
        int start ; //start表示父親節點的下標,end表示當前節點的下標,存在調用和被調用的關係
        Tracer tracer = list.get(end);
        String parentId = tracer.getParentId();
        for (int j=0;j<n;j++){
            Tracer parent = list.get(j);
             if (parent.getSpanId()!=null&&parent.getSpanId().equals(parentId)){
                start = j;
                g[start].add(end);  //如果存在這樣的一個父親節點,就添加到連通圖 g 中
                break;
            }
        }
        m ++;//邊數
    }

    /***
     * 輔助函數,查找spanId在list中存儲的下標
     * @param spanId
     * @return int index of spanId(不存在則返回 -1 )
     **/
    public int findIndex(String spanId){
        for (int i=0;i<list.size();i++){
            Tracer tracer =list.get(i);
            if (tracer.getSpanId()==null){
                throw new IllegalArgumentException("current spanId can not be \"null\"!!!");
            }
            if (tracer.getSpanId().equals(spanId)){
                return i;
            }
        }
        return -1;
    }

    // 輔助函數:驗證圖中是否有從v到w的邊
    public boolean hasEdge( int v , int w ){
        assert v >= 0 && v < n ;
        assert w >= 0 && w < n ;
        for( int i = 0 ; i < g[v].size() ; i ++ )
            if( g[v].elementAt(i) == w )
                return true;
        return false;
    }

    // 輔助函數:以領接表的形式打印圖的連接關係
    public void showTrace(){
        for( int i = 0 ; i < n ; i ++ ){
            System.out.print("vertex " + i + ":\t");
            for( int j = 0 ; j < g[i].size() ; j ++ )
                System.out.print(g[i].elementAt(j) + "\t");
            System.out.println();
        }
    }
    // 輔助函數:以領接表的形式打印圖的信息
    public void showTraceImformation(){
        for( int i = 0 ; i < n ; i ++ ){
            System.out.print("vertex " + i + ":\t");
            for( int j = 0 ; j < g[i].size() ; j ++ ) {
                int LinkeIndex = g[i].get(j);
                System.out.print(list.get(LinkeIndex) + "\t");
            }
            System.out.println();
        }
    }

    /***
     * 展示從spanId開始的所有路徑 。
     * @param spanId
     * @return:allPath
     * */
    public ArrayList<ArrayList<Integer>> showAllPath(String spanId){
        Path path = new Path(this , spanId);               //初始化路徑信息
        ArrayList<ArrayList<Integer>>allPath = path.showAllPath();//將所有路徑添加進二維鏈表中
        System.out.println(allPath);                              //打印結果
        return allPath;
    }

    //  將從spanId開始的所有路徑,整理成一顆多叉樹
    public void showTree(ArrayList<ArrayList<Integer>> allPath){
        Tree tree = new Tree(list);
        for (ArrayList<Integer>path:allPath){
            tree.add(path);
        }
        tree.preOrder();
    }

    // 輔助函數:用於遍歷
    public Iterable<Integer> adj(int v) {
        assert v >= 0 && v < n;
        return g[v];
    }

    //  輔助函數:用於判斷當前節點是不是葉子節點
    public boolean isLast(int v){
        assert v >= 0 && v < n;
        return g[v].size()==0;
    }
}

四、Tracer

package IMUHERO.DAG;

import com.sun.deploy.trace.Trace;

/**
 * 時間:2019/8/13
 * 功能:封裝tracer類作爲圖中的每一個節點,方便調用
 * 包含:traceId、parentId、spanId、duration
 */
public class Tracer {


    private String traceId;     //路徑ID
    private String parentId;    //父節點ID
    private String spanId;      //標註當前節點的ID
    private Long duration;      //持續時間
    private int depth;          //當前節點的深度
    private int index;          //圖表中的下標值
    private long startTime;     //起始時間
    private String nickName;    //暱稱
    private long phoneNum;      //電話號碼

    public Tracer(){

    }
    //輔助構造函數
//    public Tracer(Tracer tracer) {
//        this.traceId = tracer.getTraceId();
//        this.parentId = tracer.getParentId();
//        this.spanId = tracer.getSpanId();
//        this.duration = tracer.getDuration();
//        this.depth = tracer.getDepth();
//        this.index = tracer.getIndex();
//    }

    public String getTraceId(){
        return this.traceId;
    }
    public String getParentId(){
        return this.parentId;
    }
    public String getSpanId(){
        return this.spanId;
    }
    public Long getDuration(){
        return duration;
    }
    public int getIndex(){
        return index;
    }

    public int getDepth() {
        return this.depth;
    }
    public void setDepth(int depth) {
        this.depth = depth;
    }

    public void setTraceId(String traceId){
        this.traceId = traceId;
    }
    public void setParentId(String parentId){
        this.parentId = parentId;
    }
    public void setSpanId(String spanId){
        this.spanId = spanId;
    }
    public void setDuration(Long duration){
        this.duration = duration;
    }
    public void setIndex(int index){
        this.index = index;
    }

    public long getStartTime() {
        return startTime;
    }

    public String getNickName() {
        return nickName;
    }

    public long getPhoneNum() {
        return phoneNum;
    }

    public void setStartTime(long startTime) {
        this.startTime = startTime;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public void setPhoneNum(long phoneNum) {
        this.phoneNum = phoneNum;
    }

    @Override
    public String toString() {
        StringBuffer stb = new StringBuffer();
        stb.append("[[index:"+index+"]");
        stb.append("[depth:"+depth+"]]");
        stb.append("[traceId:"+traceId+"]");
        stb.append("[parentId:"+parentId+"]");
        stb.append("[spanId:"+spanId+"]");
        stb.append("[duration:"+duration+"]]");
        return stb.toString();
    }


}

五、Tree

package IMUHERO.DAG;
import java.util.ArrayList;
import java.util.HashMap;

public class Tree {

    private class Node {
        public Integer e;
        public HashMap<Integer, Node> children;

        public Node(Integer e) {
            this.e = e;
            children = new HashMap<>();//初始時爲空
        }
    }

    private Node root;
    private int size;
    private ArrayList<Tracer>list;
    private ArrayList<Tracer>treeList = new ArrayList<>();  //前序遍歷時生成的數據存儲在這裏

    public Tree() {
        root = null;
        size = 0;
    }

    public Tree(ArrayList<Tracer>list) {
        this.list = list;
        root = null;
        size = 0;
    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    // 向二分搜索樹中添加一條路徑
    public void add(ArrayList<Integer> path) {
        if (path.size() == 0) throw new IllegalArgumentException("path is empty!!!");
        if (root==null){
            root = new Node(path.get(0));
            size++;
        }
         add(root, path);
    }
    // 向以node爲根的二分搜索樹中插入元素e,遞歸算法
    // 返回插入新節點後二分搜索樹的根
    private void add(Node node, ArrayList<Integer> path) {
        //根節點在初始化的時候就必須存在
        Node cur = node;
        for (int i = 1; i < path.size(); i++) {
            int index = path.get(i);
            if (cur.children.containsKey(index)) {
                cur = cur.children.get(index);
            } else {
                cur.children.put(index, new Node(index));
                cur = cur.children.get(index);
                size++;
            }
        }
    }


    public ArrayList<Tracer> preOrder(){
        preOrder(root,0);
        System.out.println(treeList);
        return treeList;
    }
    private void preOrder(Node node ,int depth){
        if (node.children==null)return;
        StringBuffer stb = new StringBuffer();

        //以下四行代碼用於測試(可刪除)
        for (int i=0;i<depth;i++){
            stb.append("——");
        }
        System.out.println(stb.toString()+node.e);

        Tracer tracer = list.get(node.e);   //根據下標獲取對象
        tracer.setDepth(depth);
        treeList.add(tracer);

        for (HashMap.Entry<Integer,Node> map:node.children.entrySet()){
            preOrder(map.getValue(),depth+1);
        }
    }


}

 Main函數

package IMUHERO.DAG;
import java.util.ArrayList;
public class Main {
    public static void main(String[] args) {
        ArrayList<Tracer>list = new ArrayList<>();
        for (int i=0;i<5;i++){
            if (i>0){
                Tracer tracer = new Tracer();
                tracer.setTraceId(String.valueOf(0));
                tracer.setParentId(String.valueOf(i-1));
                tracer.setSpanId(String.valueOf(i));
                tracer.setDuration((long)i*100);
                tracer.setIndex(i);     //設置下標
                list.add(tracer);
            }
            else {
                Tracer tracer = new Tracer();
                tracer.setTraceId(String.valueOf(0));
                tracer.setSpanId("0");
                tracer.setDuration((long)i*100);
                tracer.setIndex(i);     //設置下標
                list.add(tracer);
            }
        }

        Tracer tracer0 =new Tracer();
        tracer0.setParentId("2");
        tracer0.setSpanId("5");
        tracer0.setIndex(5);
        tracer0.setTraceId("0");
        tracer0.setDuration((long)5*100);
        list.add(tracer0);

        Tracer tracer1 = new Tracer();
        tracer1.setTraceId(String.valueOf(0));
        tracer1.setSpanId("6");
        tracer1.setIndex(6);
        tracer1.setParentId("0");
        tracer1.setDuration((long)6*100);
        list.add(tracer1);

        Tracer tracer2 = new Tracer();
        tracer2.setTraceId(String.valueOf(7));
        tracer2.setSpanId("7");
        tracer2.setParentId("6");
        list.add(tracer2);

        System.out.println(list);

        SparseGraph sparseGraph = new SparseGraph(list);
        System.out.println("顯示連通圖:*******************************************************************************");
        sparseGraph.showTrace();
        System.out.println("顯示連通圖及包含的信息:********************************************************************");
        sparseGraph.showTraceImformation();
        System.out.println("顯示所有路徑:******************************************************************************");
        ArrayList<ArrayList<Integer>> allPath = sparseGraph.showAllPath("0");
        System.out.println("樹形結構:**********************************************************************************");
        sparseGraph.showTree(allPath);

    }
}

 

 

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