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