图(三)—— 赋权有向图的几个算法
来源:互联网 发布:动易cms模板 编辑:程序博客网 时间:2024/06/16 04:12
参考:数据结构与算法分析——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=null,visited=false; 起点s 的dist=0,其他顶点的dist=∞。每一个阶段,从所有未被访问过的顶点中选择具有最小的dist的那个记为v,v.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:
/** * 顶点类 */package com.weightgraph;import java.util.LinkedList;public class Vertex {String name; //顶点名称LinkedList<Node> adj; //存放从此顶点出发的边的信息 ,Node中有两个信息,一是边指向的顶点,二是权boolean visited; //该顶点是否被访问Vertex path; //从某一个开始顶点到此顶点的最短路径的前一个顶点 //如若此顶点是v7,开始顶点是v1,最短路径是v1-v3-v5-v7 ,则path=v5int dist; //从开始顶点到此顶点的最短距离//构造vertexpublic Vertex(String name){this.name=name;adj=new LinkedList<Node>();visited=false;path=null;dist=Graph.INFINITY;}public void reset(){visited=false;dist=Graph.INFINITY;path=null;}class Node {Vertex v;int weight; Node(Vertex v,int weight){this.v=v;this.weight=weight;}}}
Graph.java:
package com.weightgraph;import java.util.HashMap;import java.util.Iterator;import java.util.PriorityQueue;import java.util.Queue;import java.util.Map.Entry;import com.weightgraph.Vertex.Node;public class Graph {public static final int INFINITY=Integer.MAX_VALUE;//顶点名称的映射HashMap<String, Vertex> vertexMap=new HashMap<String, Vertex>();/** * 让vertexMap取得对Vertex对象的引用 * @param vertexName 顶点名称 * @return v 顶点 */private Vertex getVertex(String vertexName){Vertex v=vertexMap.get(vertexName);if(v==null){v=new Vertex(vertexName);vertexMap.put(vertexName,v);}return v;}/** * 找出未被访问的顶点的dist最小的一个 * @return Vertex vt */private Vertex findMin(){int minDist=Graph.INFINITY;;Vertex vt = null;for(Iterator<Vertex> itr=vertexMap.values().iterator(); itr.hasNext();){Vertex v=itr.next();if(v.visited==false && v.dist<minDist ){minDist=v.dist;vt=v;}}return vt;}/** * 显示最短路径 * @param dest 终点顶点 */private void printPath(Vertex dest){if(dest.path!=null){ printPath(dest.path);System.out.print("-");}System.out.print(dest.name);}/** * 返回所有顶点中第一个未被访问的顶点,如果全部被访问则返回null * @return Vertex */private Vertex firstUnvisited(){for(Iterator<Vertex> itr=vertexMap.values().iterator();itr.hasNext();){Vertex vertex=itr.next();if(vertex.visited==false)return vertex;}return null;}/** * 某一顶点后的所有顶点是否都被访问 * @param Vertex v * @return boolean */private boolean isAllVisited(Vertex v){boolean result=true;if(v.visited==false)return false;else{for(Iterator<Node> itr=v.adj.iterator();itr.hasNext();){Node node=itr.next();if(node.v.visited==false)result=false;}}return result;}/** * 深度优先遍历方法 * @param start 遍历的起点 */private void DFSearch(Vertex start){ if(start.visited==false){System.out.print(start.name+" ");start.visited=true;}for(Iterator<Node> itr=start.adj.iterator();itr.hasNext();){Node node=itr.next();if(node.v.visited==false){DFSearch(node.v);}}if(firstUnvisited()!=null) DFSearch(firstUnvisited()); }/** * 广度优先遍历方法 * @param start 遍历的起点 */private void BFSearch(Vertex start){ if(start.visited==false){System.out.print(start.name+" ");start.visited=true;}for(Iterator<Node> itr=start.adj.iterator();itr.hasNext();){Node node=itr.next();if(node.v.visited==false){System.out.print(node.v.name+" ");node.v.visited=true;}}for(Iterator<Node> itr=start.adj.iterator();itr.hasNext();){Node node=itr.next();if(!isAllVisited(node.v)) BFSearch(node.v);} if(firstUnvisited()!=null) BFSearch(firstUnvisited());}/** * 初始化 */public void clearAll(){for(Iterator<Vertex> itr=vertexMap.values().iterator();itr.hasNext();){itr.next().reset();}}/** * 增加一条边 * @param sourceName 起点 * @param destName 终点 * @param weight 权 */public void addEdge(String sourceName,String destName,int weight){Vertex v=getVertex(sourceName); //起点Vertex w=getVertex(destName); //终点Node node=v.new Node(w,weight); v.adj.add(node);} /** * Dijkstra(迪卡斯特拉)算法计算最短路径 * @param startVerName 起点 */public void dijkstra(String startVerName){clearAll();System.out.println("以"+startVerName+"为起点:");Vertex start=getVertex(startVerName);start.dist=0;while(true){Vertex ver=findMin();if (ver==null)break;ver.visited=true;for(Iterator<Node> itr=ver.adj.iterator();itr.hasNext();){Node node=itr.next();if(node.v.visited==false && ver.dist+node.weight<node.v.dist){node.v.dist=ver.dist+node.weight;node.v.path=ver;}}}}/** * 打印最短路径 * @param destName 终点 */public void printShortestPath(String destName){System.out.print("到 "+destName+" 的最短路径:");Vertex dest=getVertex(destName);if(dest==null){System.out.println("不存在该终点顶点!");}else{printPath(dest);}System.out.print("\t 路径长:"+dest.dist);System.out.println();}/** * 深度优先遍历 * @param startName 起点 */public void DFS(String startName){clearAll();System.out.println("以"+startName+"为起点深度优先遍历图:");Vertex start=getVertex(startName);DFSearch(start);System.out.println();}/** * 广度优先遍历 * @param startName 起点 */public void BFS(String startName){clearAll();System.out.println("以"+startName+"为起点广度优先遍历图:");Vertex start=getVertex(startName);BFSearch(start);System.out.println();}/** * 拓扑排序算法 */public void topSort(){clearAll();//放拓扑排序的各个顶点名Queue<String> topsort=new PriorityQueue<String>(); //首先计算各顶点的入度HashMap<String,Integer> inDegree=new HashMap<String, Integer>();for(Iterator<Vertex> itr=vertexMap.values().iterator();itr.hasNext();){Vertex vertex=itr.next();if(inDegree.get(vertex.name)==null)inDegree.put(vertex.name, 0);for(Iterator<Node> inode=vertex.adj.iterator();inode.hasNext();){Node temp=inode.next();int i;if(inDegree.get(temp.v.name)==null)i=0;else {i=inDegree.get(temp.v.name);}inDegree.put(temp.v.name, ++i);}}//队列,用来放入度为0的顶点名Queue<String> q=new PriorityQueue<String>();for(Iterator<Entry<String, Integer>> itr=inDegree.entrySet().iterator();itr.hasNext();){Entry<String, Integer> entry=itr.next();int degree=entry.getValue();if(degree==0){q.offer(entry.getKey());}}if(q.size()==0)System.out.println("该图有圈,没有拓扑排序!");while(!q.isEmpty()){String deQueueVerName=q.poll();//打印出队//System.out.print(deQueueVerName+" ");topsort.offer(deQueueVerName);getVertex(deQueueVerName).visited=true;for(Iterator<Node> itr=getVertex(deQueueVerName).adj.iterator();itr.hasNext();){Node node=itr.next();int degree=inDegree.get(node.v.name);inDegree.put(node.v.name, --degree);if(degree==0)q.offer(node.v.name);}if(q.size()==0 && firstUnvisited()!=null)System.out.println("该图有圈,没有拓扑排序!");}//打印出拓扑排序 topsort中的顶点数等于图中的顶点数才说明图中没有圈if(topsort.size()==vertexMap.size()){for(Iterator<String> itr=topsort.iterator();itr.hasNext();){System.out.print(itr.next()+" ");}}}}
Main.java:
package com.weightgraph;public class Main {public static void main(String[] args) { //构建图 Graph graph=new Graph(); graph.addEdge("v1", "v2",2); graph.addEdge("v1", "v4",1); graph.addEdge("v2", "v4",3); graph.addEdge("v2", "v5",10); graph.addEdge("v3", "v1",4); graph.addEdge("v3", "v6",5); graph.addEdge("v4", "v3",2); graph.addEdge("v4", "v5",2); graph.addEdge("v4", "v6",8); graph.addEdge("v4", "v7",4); graph.addEdge("v5", "v7",6); graph.addEdge("v7", "v6",1); System.out.println("**********graph***************"); // dijkstra算法计算最短路径 ,起点 v1 graph.dijkstra("v1"); //打印从v1到个顶点的最短路径 for(int i=1;i<=7;i++){ graph.printShortestPath("v"+i); } //以v3为起点广度优先遍历图 graph.BFS("v3"); //以v3为起点深度优先遍历图 graph.DFS("v3"); System.out.println(); //graph的拓扑排序 graph.topSort(); //构建另一个无圈的图graph2,可以打印出拓扑排序 Graph graph2=new Graph(); graph2.addEdge("v1", "v2",2); graph2.addEdge("v1", "v4",1); graph2.addEdge("v1", "v3",3); graph2.addEdge("v2", "v4",10); graph2.addEdge("v2", "v5",4); graph2.addEdge("v3", "v6",5); graph2.addEdge("v4", "v3",2); graph2.addEdge("v4", "v6",8); graph2.addEdge("v4", "v7",4); graph2.addEdge("v5", "v4",2); graph2.addEdge("v5", "v7",6); graph2.addEdge("v7", "v6",1); System.out.println("**********graph2***************"); System.out.println("graph2的拓扑排序:"); graph2.topSort(); Graph graph3=new Graph(); graph3.addEdge("v1", "v2",2); graph3.addEdge("v2", "v4",10); graph3.addEdge("v4", "v3",2); graph3.addEdge("v3", "v2",3); System.out.println(); System.out.println("**********graph3***************"); System.out.println("graph3的拓扑排序:"); graph3.topSort(); }}
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的拓扑排序:
该图有圈,没有拓扑排序!
- 图(三)—— 赋权有向图的几个算法
- 图(三)—— 赋权有向图的几个算法
- 无向图的几个基本算法应用
- 有向图的几个算法分析总结
- 有向图的几个算法分析总结
- 有向图强连通分量的三种算法
- 【算法理解】—— 快速排序(三向切分)
- 隐马尔可夫模型(三)——隐马尔可夫模型的评估问题(前向算法)
- 隐马尔可夫模型(三)——隐马尔可夫模型的评估问题(前向算法)
- 隐马尔可夫模型(三)——隐马尔可夫模型的评估问题(前向算法)
- 图的存储三部曲——其三:静态建表(链式前向星)
- 关于图的几个算法
- 数据结构——有向图(拓扑排序算法)
- 小白学算法3.3——三向字符串快速排序
- 图(二)—— 一个有向无权图的最短路径算法
- 图(二)—— 一个有向无权图的最短路径算法
- poj1523—SPF(tarjan算法求无向图中所有的割点)
- 无向图的最短路径求解算法之——Dijkstra算法
- Jmagick图形图像处理【转载自hu_shengyang的文章】
- 访问者模式
- 存储过程:把所有表名连接到一个单一字符串的存储过程
- C++ vector 用法汇总
- 每半月一个分区,自动维护
- 图(三)—— 赋权有向图的几个算法
- 编译 QGIS 1.7.0
- mysql更改用户名和密码及mysql常用命令
- 把文件打包长apk2文件
- nginx配置rewrite时报directive “rewrite” is not terminated by “;”
- HTML5学习(6) 表单元素
- 年轻创业者常犯的七宗罪
- 代理模式
- C# 字符串去掉重复