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);

    }
}
发布了159 篇原创文章 · 获赞 41 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_37768971/article/details/102632769
DAG