遍历有向无环图,寻找最优路径:

1、假设我们从A点走到B点,可以经过不同的地方,分别用1,2,3,4,5,6表示,A用0表示,B用7表示,从一个地方到另一个地方,中间的路好走的程度用w表示,w越大表示越好走,因此我们可以建立数学模型如下图1所示:

java 判断有向无环图 有向无环图遍历_遍历



图1

2、根据数学模型,我们判断这是一个有向无环图遍历问题,有向无环图遍历有两种方法,(1)、广度优先(BFS)、(2)、深度优先(DFS)而我们需要的结果是从A到B那个路径的w值最大,即输出结果是路径:0->1->3->7,权值1+3+7=11。最后我们只需要选出权值和最大的路径即可,DFS正好适合这种输出结果,而且时间复杂度为O(V+E)。java代码实现如下:

3、创建有向无环图节点

package answer.graph.model;
 
import java.util.ArrayList;
import java.util.List;
 
/**
 * 节点
 * @author willWang
 * @Date 2017-11-23
 */
public  class GraphNode {
 
    public List<GraphEdge> edgeList = null;
    
    private String label = "";
    
    public GraphNode(String label) {
       this.label = label;
       if (edgeList == null) {
edgeList = new ArrayList<GraphEdge>();
       }
    }
    
/**
     * 给节点添加边
     * @author willWang
     * @date 2017-11-23
     * @param edge
     */
    public  void addEdgeList(GraphEdge edge) {
edgeList.add(edge);
    }
    
/**
     * 获取节点标签
     * @author willWang
     * @date 2017-11-23
     * @return
     */
    public String getLabel() {
       return label;
    }
}
         4、创建有向无环图的边
package answer.graph.model;
 
/**
 * 创建有向无环图边
 * @author willWang
 *
 */
public  class GraphEdge {
 
//左侧节点
    private GraphNode nodeLeft;
//右侧节点
    private GraphNode nodeRight;
//权重
    private  int weight;
 
/**
     * 初始化边
     * @author wwy
     * @date 2017-11-23
     * @param nodeLeft
     * @param nodeRight
     * @param weight
     */
    public GraphEdge(GraphNode nodeLeft, GraphNode  nodeRight, int  weight) {
       this.nodeLeft = nodeLeft;
       this.nodeRight = nodeRight;
       this.weight = weight;
    }
 
    public GraphNode getNodeLeft() {
       return nodeLeft;
    }
 
    public GraphNode getNodeRight() {
       return nodeRight;
    }
    
    public  int getWeight() {
       return weight;
    }
}
    5、根据设计初始化有向无环图
package answer.graph.model;
 
import java.util.ArrayList;
import java.util.List;
 
/**
 * 按照设计图构造有向无环图
 * @author willWang
 * @Date 2017-11-23
 */
public  class MyGraph {
 
    private List<GraphNode> nodes = null;
    
    public  void initGraph(int n) {
       if (nodes == null) {
nodes = new ArrayList<GraphNode>();
       }
       
node = null;
       for (int i = 0; i <  n; i++) {
node = new GraphNode(String.valueOf(i));
nodes.add(node);
       }
    }
    
    public  void initGraph(int n, boolean b) {
n);
edge01 = new GraphEdge(nodes.get(0), nodes.get(1), 1);
edge02 = new GraphEdge(nodes.get(0), nodes.get(2), 2);
edge13 = new GraphEdge(nodes.get(1), nodes.get(3), 3);
edge14 = new GraphEdge(nodes.get(1), nodes.get(4), 4);
edge25 = new GraphEdge(nodes.get(2), nodes.get(5), 5);
edge26 = new GraphEdge(nodes.get(2), nodes.get(6), 6);
edge37 = new GraphEdge(nodes.get(3), nodes.get(7), 7);
edge47 = new GraphEdge(nodes.get(4), nodes.get(7), 8);
edge57 = new GraphEdge(nodes.get(5), nodes.get(7), 9);
edge67 = new GraphEdge(nodes.get(6), nodes.get(7), 10);
       
       
nodes.get(0).addEdgeList(edge01);
nodes.get(0).addEdgeList(edge02);
nodes.get(1).addEdgeList(edge13);
nodes.get(1).addEdgeList(edge14);
nodes.get(2).addEdgeList(edge25);
nodes.get(2).addEdgeList(edge26);
nodes.get(3).addEdgeList(edge37);
nodes.get(4).addEdgeList(edge47);
nodes.get(5).addEdgeList(edge57);
nodes.get(6).addEdgeList(edge67);
    }
    
    public  void initGraph() {
       initGraph(8, false);
    }
    
    public List<GraphNode> getGraphNodes() {
       return nodes;
    }
}
         6、重点来了,根据深度优先算法遍历有向无环图,并计算出最优路径
package answer.graph.traversing;
 
import java.util.List;
 
import answer.graph.model.GraphEdge;
import answer.graph.model.GraphNode;
 
/**
 * 采用深度优先算法获取最佳路径
 * @author wwy
 * @Date 2017-11-23
 */
public  class DFSGetBestPath {
    
    private  int tempWeight
    int  maxWeight
result =  "";
    private StringBuffer wsb = new StringBuffer();
    private StringBuffer lsb = new StringBuffer();
    
    public String getResult() {
       return result;
    }
 
/**
     * 采用深度优先算法递归遍历有向无环图
     * @param node
     * @param visited
     * @return
     */
    public GraphNode searchTraversing(GraphNode node,List<GraphNode>  visited) {
// 如果已经查看过该节点,返回该节点
       if (visited.contains(node)) {
           return node;
       }
       
visited.add(node);
//添加节点示例
       if(lsb.length() > 0){
lsb.append("->");
       }
lsb.append(node.getLabel());
//     System.out.println("节点:" + node.getLabel());
       if(node.edgeList.size() > 0){
           for (int i = 0; i <  node.edgeList.size();  i++) {
gEdge = node.edgeList.get(i);
              int weight = gEdge.getWeight();
//计算当前路径权重
tempWeight +=  weight;
//添加权重示例
              if(wsb.length() > 0){
wsb.append("+");
              }
wsb.append(weight);
              
nextNode = searchTraversing(gEdge.getNodeRight(), visited);
              if(nextNode.getLabel() != null &&  nextNode.getLabel() != ""){
//减去退出路径的权重
tempWeight -= weight;
//删除退出路径的权重示例
                  if(wsb.length() <= 1){
wsb.delete(wsb.length()-1, wsb.length());
                  }else{
wsb.delete(wsb.length()-2, wsb.length());
                  }
//删除退出路径的节点示例
                  if(lsb.length() <= 1){
lsb.delete(lsb.length()-1, lsb.length());
                  }else{
lsb.delete(lsb.length()-3, lsb.length());
                  }
              }
//删除当前节点,为遍历其他路径上的节点做准备
visited.remove(nextNode);
           }
       }else{
           if(maxWeight < tempWeight){
maxWeight =  tempWeight;//更细最大权重
//更新最有路径结果
result =  maxWeight+"(最优路径是:"+lsb.toString()+"权重之和是:"+wsb.toString()+"="+maxWeight+")";
           }
       }
       return node;
    }
}
    7、测试代码
public  class Main {
 
    private  static MyGraph graph = null;
    
/**
     * 初始化有向无环图
     * @author willWang
     * @date 2017-11-23
     */
    private  static void initGraph() {
       if (graph == null) {
           graph = new MyGraph();
       }
       
       graph.initGraph();
    }
    
    public  static void main(String[]  args) {
//初始化有向无环图
       initGraph();
visited = new ArrayList<GraphNode>();
       
       System.out.println("深度优先算法");
graph.getGraphNodes().get(0)
mdfs = new DFSGetBestPath();
       GraphNode result = mdfs.searchTraversing(graph.getGraphNodes().get(0), visited);
       System.out.println(mdfs.getResult());
}
}

         8、输出结果:

起点:

0

输出:18(最优路径是:0->2->6->7权重之和是:2+6+10=18)