图(三)—— 赋权有向图的几个算法

参考:数据结构与算法分析——Java语言描述  (Mark Allen Weis 

       包括:

        1、Djkstra算法求最短路径

        2、深度优先遍历

        3、广度优先遍历

        4、拓扑排序算法

        一、Djkstra算法

        顶点类有三个属性值得注意:①boolean visited,表示该顶点是否被访问 ②Vertex path,从某一个开始顶点到此顶点的最短路径的前一个顶点,如若此顶点是v7,开始顶点是v1,最短路径是v1-v3-v5-v7 ,则path=v5  ③ int dist从起点到此顶点的最短距离。

         初始状态时,所有顶点的 path=nullvisited=false; 起点dist=0,其他顶点的dist=。每一个阶段,从所有未被访问过的顶点中选择具有最小的dist的那个记为vv.visited=true,遍历它的所有相邻顶点w,如果v.dist+w.dist<w.dist ,那么w.dist=v.dist+w.dist ,同时w.path=v

        二、深度优先遍历

        假定给定图G的初态是所有顶点均未曾访问过,在G中任选一顶点v为出发点,则深度优先搜索可定义如下:从指定的起点v出发(先访问v,并将其标记为已访问过),访问它的任意相邻接的顶点w1,再访问w1的任一个未访问的相邻接顶点w2,如此下去,直到某顶点的所有相邻接的顶点都被访问过的,就回溯到它的前驱。如果这个访问和回溯过程返回到遍历开始的顶点,就结束遍历过程。如果图中仍存在一些未访问过的顶点,就另选一个未访问过的顶点重新开始深度优先搜素。

        三、广度优先遍历

        假定给定图G的初态是所有顶点均未曾访问过,在G中任选一顶点v为出发点,则广度优先搜索可定义如下:从指定的起点v出发,访问与它相邻接的所有顶点w1,w2,……;然后再再依次访问w1,w2,……邻接的尚未被访问的所有顶点,重复这一过程,直到所有的顶点都被访问过为止。如果图中仍存在一些未访问过的顶点,就另选一个未访问过的顶点重新开始广度优先搜素。

        四、拓扑排序算法

        拓扑排序(topological sort)是对有向无圈图的顶点的一种排序,它使得如果存在一条从vi 到vj的路径,那么排序中vj出现在Vi的后面。显然,如果图含有圈,那么拓扑排序是不可能的。

        一个简单的求拓扑排序的算法是:首先计算每个顶点的入度,然后将所有入度为0的顶点放入一个初始为空的队列中。当队列不为空时,删除队首的顶点v,并将v的邻接的所有顶点的入度减1,只要入度降为0,就把该顶点放入队列中。拓扑排序就是顶点出队的顺序。

 

        代码:

        Vertex.java:

[java]  view plain copy
  1. /** 
  2.  * 顶点类 
  3.  */  
  4. package com.weightgraph;  
  5.   
  6. import java.util.LinkedList;  
  7.   
  8. public class Vertex {  
  9.       
  10.     String name;  //顶点名称  
  11.     LinkedList<Node>  adj;   //存放从此顶点出发的边的信息    ,Node中有两个信息,一是边指向的顶点,二是权  
  12.     boolean visited;   //该顶点是否被访问  
  13.     Vertex path;       //从某一个开始顶点到此顶点的最短路径的前一个顶点  
  14.                        //如若此顶点是v7,开始顶点是v1,最短路径是v1-v3-v5-v7 ,则path=v5  
  15.       
  16.     int dist;          //从开始顶点到此顶点的最短距离  
  17.   
  18.     //构造vertex  
  19.     public Vertex(String name){  
  20.           
  21.         this.name=name;  
  22.         adj=new LinkedList<Node>();  
  23.         visited=false;  
  24.         path=null;  
  25.         dist=Graph.INFINITY;  
  26.     }  
  27.     public void reset(){  
  28.           
  29.         visited=false;  
  30.         dist=Graph.INFINITY;  
  31.         path=null;  
  32.     }  
  33.       
  34.     class Node {          
  35.         Vertex v;  
  36.         int weight;  
  37.           
  38.         Node(Vertex v,int weight){  
  39.               
  40.             this.v=v;  
  41.             this.weight=weight;  
  42.               
  43.         }  
  44.     }  
  45. }  

        Graph.java:

[java]  view plain copy
  1. package com.weightgraph;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Iterator;  
  5. import java.util.PriorityQueue;  
  6. import java.util.Queue;  
  7. import java.util.Map.Entry;  
  8.   
  9. import com.weightgraph.Vertex.Node;  
  10.   
  11. public class Graph {  
  12.       
  13.     public static final int INFINITY=Integer.MAX_VALUE;  
  14.       
  15.     //顶点名称的映射     
  16.     HashMap<String, Vertex> vertexMap=new HashMap<String, Vertex>();  
  17.       
  18.     /** 
  19.      * 让vertexMap取得对Vertex对象的引用 
  20.      * @param vertexName   顶点名称 
  21.      * @return v           顶点 
  22.      */  
  23.     private Vertex getVertex(String vertexName){  
  24.           
  25.         Vertex v=vertexMap.get(vertexName);  
  26.         if(v==null)  
  27.         {  
  28.             v=new Vertex(vertexName);  
  29.             vertexMap.put(vertexName,v);  
  30.         }  
  31.         return v;         
  32.     }  
  33.       
  34.     /** 
  35.      * 找出未被访问的顶点的dist最小的一个 
  36.      * @return  Vertex vt 
  37.      */  
  38.     private Vertex findMin(){  
  39.           
  40.         int minDist=Graph.INFINITY;;  
  41.         Vertex vt = null;  
  42.         for(Iterator<Vertex> itr=vertexMap.values().iterator();  
  43.              itr.hasNext();)  
  44.         {  
  45.             Vertex v=itr.next();  
  46.             if(v.visited==false && v.dist<minDist )  
  47.             {  
  48.                 minDist=v.dist;  
  49.                 vt=v;  
  50.             }  
  51.         }  
  52.         return vt;  
  53.     }  
  54.       
  55.     /** 
  56.      * 显示最短路径 
  57.      * @param dest 终点顶点 
  58.      */  
  59.     private void printPath(Vertex dest){  
  60.                   
  61.         if(dest.path!=null)  
  62.         {             
  63.             printPath(dest.path);  
  64.             System.out.print("-");            
  65.         }  
  66.         System.out.print(dest.name);  
  67.     }  
  68.     /** 
  69.      * 返回所有顶点中第一个未被访问的顶点,如果全部被访问则返回null 
  70.      * @return Vertex 
  71.      */  
  72.     private Vertex firstUnvisited(){  
  73.           
  74.         for(Iterator<Vertex> itr=vertexMap.values().iterator();itr.hasNext();)  
  75.         {  
  76.             Vertex vertex=itr.next();  
  77.             if(vertex.visited==false)  
  78.                 return vertex;  
  79.         }  
  80.         return null;  
  81.     }  
  82.     /** 
  83.      * 某一顶点后的所有顶点是否都被访问 
  84.      * @param Vertex v 
  85.      * @return boolean 
  86.      */  
  87.     private boolean isAllVisited(Vertex v){  
  88.           
  89.         boolean result=true;  
  90.         if(v.visited==false)  
  91.             return false;  
  92.         else{  
  93.             for(Iterator<Node> itr=v.adj.iterator();itr.hasNext();)  
  94.             {  
  95.                 Node node=itr.next();  
  96.                 if(node.v.visited==false)  
  97.                     result=false;             
  98.             }  
  99.         }  
  100.         return result;        
  101.     }  
  102.       
  103.     /** 
  104.      * 深度优先遍历方法 
  105.      * @param start  遍历的起点 
  106.      */  
  107.     private void DFSearch(Vertex start){  
  108.           
  109.           if(start.visited==false)  
  110.             {  
  111.                 System.out.print(start.name+" ");  
  112.                 start.visited=true;  
  113.             }  
  114.             for(Iterator<Node> itr=start.adj.iterator();itr.hasNext();)  
  115.             {  
  116.                 Node node=itr.next();  
  117.                 if(node.v.visited==false)  
  118.                 {  
  119.                     DFSearch(node.v);  
  120.                 }  
  121.             }  
  122.             if(firstUnvisited()!=null)  
  123.                 DFSearch(firstUnvisited());  
  124.        
  125.           
  126.     }  
  127.       
  128.       
  129.       
  130.     /** 
  131.      * 广度优先遍历方法 
  132.      * @param start  遍历的起点 
  133.      */  
  134.     private void BFSearch(Vertex start){  
  135.                     
  136.           if(start.visited==false)  
  137.             {  
  138.                 System.out.print(start.name+" ");  
  139.                 start.visited=true;  
  140.             }  
  141.             for(Iterator<Node> itr=start.adj.iterator();itr.hasNext();)  
  142.             {  
  143.                 Node node=itr.next();  
  144.                 if(node.v.visited==false)  
  145.                 {  
  146.                     System.out.print(node.v.name+" ");  
  147.                     node.v.visited=true;  
  148.                       
  149.                 }  
  150.             }  
  151.             for(Iterator<Node> itr=start.adj.iterator();itr.hasNext();)  
  152.             {  
  153.                 Node node=itr.next();  
  154.                 if(!isAllVisited(node.v))  
  155.                   BFSearch(node.v);  
  156.             }  
  157.             if(firstUnvisited()!=null)  
  158.                 BFSearch(firstUnvisited());  
  159.     }  
  160.       
  161.       
  162.     /** 
  163.      * 初始化  
  164.      */  
  165.     public void clearAll(){  
  166.           
  167.         for(Iterator<Vertex> itr=vertexMap.values().iterator();itr.hasNext();)  
  168.         {  
  169.             itr.next().reset();  
  170.         }  
  171.     }  
  172.           
  173.     /** 
  174.      * 增加一条边 
  175.      * @param sourceName 起点 
  176.      * @param destName   终点 
  177.      * @param weight     权 
  178.      */  
  179.     public void addEdge(String sourceName,String destName,int weight){  
  180.           
  181.         Vertex v=getVertex(sourceName); //起点  
  182.         Vertex w=getVertex(destName);   //终点  
  183.         Node node=v.new Node(w,weight);       
  184.         v.adj.add(node);          
  185.     }  
  186.       
  187.     /** 
  188.      * Dijkstra(迪卡斯特拉)算法计算最短路径 
  189.      * @param startVerName  起点 
  190.      */  
  191.     public void dijkstra(String startVerName){  
  192.           
  193.         clearAll();  
  194.         System.out.println("以"+startVerName+"为起点:");  
  195.         Vertex start=getVertex(startVerName);  
  196.         start.dist=0;  
  197.         while(true){  
  198.               
  199.             Vertex ver=findMin();  
  200.             if (ver==null)  
  201.                 break;  
  202.             ver.visited=true;  
  203.               
  204.             for(Iterator<Node> itr=ver.adj.iterator();itr.hasNext();)  
  205.             {  
  206.                 Node node=itr.next();  
  207.                 if(node.v.visited==false && ver.dist+node.weight<node.v.dist)  
  208.                 {  
  209.                     node.v.dist=ver.dist+node.weight;  
  210.                     node.v.path=ver;  
  211.                 }  
  212.             }  
  213.         }  
  214.     }  
  215.     /** 
  216.      * 打印最短路径 
  217.      * @param destName  终点 
  218.      */  
  219.     public void printShortestPath(String destName){  
  220.           
  221.         System.out.print("到 "+destName+" 的最短路径:");  
  222.         Vertex dest=getVertex(destName);  
  223.         if(dest==null){  
  224.             System.out.println("不存在该终点顶点!");  
  225.         }else{            
  226.             printPath(dest);  
  227.         }  
  228.         System.out.print("\t 路径长:"+dest.dist);  
  229.         System.out.println();  
  230.     }  
  231.       
  232.     /** 
  233.      * 深度优先遍历 
  234.      * @param startName  起点 
  235.      */  
  236.     public void DFS(String startName){  
  237.           
  238.         clearAll();  
  239.         System.out.println("以"+startName+"为起点深度优先遍历图:");  
  240.         Vertex start=getVertex(startName);  
  241.         DFSearch(start);  
  242.         System.out.println();  
  243.     }  
  244.           
  245.     /** 
  246.      * 广度优先遍历 
  247.      * @param startName   起点 
  248.      */  
  249.     public void BFS(String startName){  
  250.           
  251.         clearAll();  
  252.         System.out.println("以"+startName+"为起点广度优先遍历图:");  
  253.         Vertex start=getVertex(startName);  
  254.         BFSearch(start);  
  255.         System.out.println();  
  256.     }  
  257.       
  258.     /** 
  259.      * 拓扑排序算法 
  260.      */  
  261.     public void topSort(){  
  262.           
  263.         clearAll();  
  264.         //放拓扑排序的各个顶点名  
  265.         Queue<String> topsort=new PriorityQueue<String>();  
  266.        //首先计算各顶点的入度  
  267.         HashMap<String,Integer> inDegree=new  HashMap<String, Integer>();  
  268.         for(Iterator<Vertex> itr=vertexMap.values().iterator();itr.hasNext();)  
  269.         {  
  270.             Vertex vertex=itr.next();  
  271.             if(inDegree.get(vertex.name)==null)  
  272.                 inDegree.put(vertex.name, 0);  
  273.               
  274.               
  275.             for(Iterator<Node> inode=vertex.adj.iterator();inode.hasNext();)  
  276.             {  
  277.                   
  278.                 Node temp=inode.next();  
  279.                 int i;  
  280.                 if(inDegree.get(temp.v.name)==null)  
  281.                     i=0;  
  282.                 else {  
  283.                     i=inDegree.get(temp.v.name);  
  284.                 }     
  285.                 inDegree.put(temp.v.name, ++i);  
  286.             }  
  287.               
  288.         }  
  289.           
  290.         //队列,用来放入度为0的顶点名  
  291.         Queue<String> q=new PriorityQueue<String>();  
  292.         for(Iterator<Entry<String, Integer>> itr=inDegree.entrySet().iterator();itr.hasNext();)  
  293.         {  
  294.             Entry<String, Integer> entry=itr.next();  
  295.             int degree=entry.getValue();  
  296.             if(degree==0){    
  297.                 q.offer(entry.getKey());  
  298.             }  
  299.                   
  300.         }  
  301.         if(q.size()==0)  
  302.             System.out.println("该图有圈,没有拓扑排序!");  
  303.         while(!q.isEmpty())  
  304.         {  
  305.             String deQueueVerName=q.poll();  
  306.             //打印出队  
  307.             //System.out.print(deQueueVerName+" ");  
  308.             topsort.offer(deQueueVerName);  
  309.             getVertex(deQueueVerName).visited=true;  
  310.             for(Iterator<Node> itr=getVertex(deQueueVerName).adj.iterator();itr.hasNext();)  
  311.             {  
  312.                 Node node=itr.next();  
  313.                 int degree=inDegree.get(node.v.name);  
  314.                 inDegree.put(node.v.name, --degree);  
  315.                 if(degree==0)  
  316.                     q.offer(node.v.name);  
  317.             }  
  318.             if(q.size()==0 && firstUnvisited()!=null)  
  319.                 System.out.println("该图有圈,没有拓扑排序!");  
  320.         }  
  321.         //打印出拓扑排序  topsort中的顶点数等于图中的顶点数才说明图中没有圈  
  322.         if(topsort.size()==vertexMap.size()){  
  323.             for(Iterator<String> itr=topsort.iterator();itr.hasNext();)  
  324.             {  
  325.                 System.out.print(itr.next()+" ");  
  326.             }  
  327.         }         
  328.     }  
  329. }  

         Main.java:

[java]  view plain copy
  1. package com.weightgraph;  
  2.   
  3. public class Main {  
  4.   
  5.     public static void main(String[] args) {  
  6.   
  7.           //构建图  
  8.           Graph graph=new Graph();  
  9.           graph.addEdge("v1""v2",2);  
  10.           graph.addEdge("v1""v4",1);  
  11.           graph.addEdge("v2""v4",3);  
  12.           graph.addEdge("v2""v5",10);  
  13.           graph.addEdge("v3""v1",4);  
  14.           graph.addEdge("v3""v6",5);  
  15.           graph.addEdge("v4""v3",2);  
  16.           graph.addEdge("v4""v5",2);  
  17.           graph.addEdge("v4""v6",8);  
  18.           graph.addEdge("v4""v7",4);  
  19.           graph.addEdge("v5""v7",6);  
  20.           graph.addEdge("v7""v6",1);  
  21.   
  22.             
  23.           System.out.println("**********graph***************");  
  24.           // dijkstra算法计算最短路径 ,起点 v1  
  25.           graph.dijkstra("v1");  
  26.             
  27.           //打印从v1到个顶点的最短路径   
  28.           for(int i=1;i<=7;i++){  
  29.               graph.printShortestPath("v"+i);  
  30.           }     
  31.             
  32.           //以v3为起点广度优先遍历图  
  33.           graph.BFS("v3");  
  34.           //以v3为起点深度优先遍历图  
  35.           graph.DFS("v3");  
  36.           System.out.println();  
  37.           //graph的拓扑排序  
  38.           graph.topSort();  
  39.             
  40.           //构建另一个无圈的图graph2,可以打印出拓扑排序  
  41.           Graph graph2=new Graph();  
  42.           graph2.addEdge("v1""v2",2);  
  43.           graph2.addEdge("v1""v4",1);  
  44.           graph2.addEdge("v1""v3",3);  
  45.           graph2.addEdge("v2""v4",10);  
  46.           graph2.addEdge("v2""v5",4);  
  47.           graph2.addEdge("v3""v6",5);  
  48.           graph2.addEdge("v4""v3",2);  
  49.           graph2.addEdge("v4""v6",8);  
  50.           graph2.addEdge("v4""v7",4);  
  51.           graph2.addEdge("v5""v4",2);  
  52.           graph2.addEdge("v5""v7",6);  
  53.           graph2.addEdge("v7""v6",1);  
  54.             
  55.           System.out.println("**********graph2***************");  
  56.           System.out.println("graph2的拓扑排序:");  
  57.           graph2.topSort();   
  58.             
  59.             
  60.           Graph graph3=new Graph();  
  61.      graph3.addEdge("v1""v2",2);  
  62.           graph3.addEdge("v2""v4",10);  
  63.           graph3.addEdge("v4""v3",2);  
  64.           graph3.addEdge("v3""v2",3);  
  65.           System.out.println();  
  66.           System.out.println("**********graph3***************");  
  67.           System.out.println("graph3的拓扑排序:");  
  68.           graph3.topSort();   
  69.     }     
  70. }  


 

         graph:   

        graph2:

        graph3:

        运行结果:

**********graph***************
以v1为起点:
到 v1 的最短路径:v1  路径长:0
到 v2 的最短路径:v1-v2  路径长:2
到 v3 的最短路径:v1-v4-v3  路径长:3
到 v4 的最短路径:v1-v4  路径长:1
到 v5 的最短路径:v1-v4-v5  路径长:3
到 v6 的最短路径:v1-v4-v7-v6  路径长:6
到 v7 的最短路径:v1-v4-v7  路径长:5
以v3为起点广度优先遍历图:
v3 v1 v6 v2 v4 v5 v7 
以v3为起点深度优先遍历图:
v3 v1 v2 v4 v5 v7 v6

该图有圈,没有拓扑排序!
**********graph2***************
graph2的拓扑排序:
v1 v2 v5 v4 v3 v7 v6 
**********graph3***************
graph3的拓扑排序:
该图有圈,没有拓扑排序!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值