目錄
一、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);
}
}