图的遍历就是从图中某个顶点出发,按某种方法对图中所有顶点访问且仅访问一次。
图的遍历算法是求解图的连通性问题、拓扑排序和求关键路径等算法的基础,也可以用作网页的爬虫技术,
图的遍历算法是求解图的连通性问题、拓扑排序和求关键路径等算法的基础,也可以用作网页的爬虫技术,
深度优先遍历(depth-first search):类似于树的先根遍历,是树的先根遍历的推广,从一个图节点去访问它的邻接节点,
知道没有邻接节点后再回溯,然后继续向下访问(一般用栈的方式来实现)
广度优先遍历(breadth-first search):遍历类似于树的层次遍历,它是树的按层遍历的推广(一般用队列的方式实现)
广度优先遍历(breadth-first search):遍历类似于树的层次遍历,它是树的按层遍历的推广(一般用队列的方式实现)
在这个例子中,深度优先遍历是最右边的节点优先访问
1 package graph; 2 3 import java.util.Arrays; 4 import java.util.HashMap; 5 import java.util.LinkedList; 6 import java.util.List; 7 import java.util.Map; 8 import java.util.Queue; 9 import java.util.Stack; 10 11 12 public class Graph { 13 //声明一个map集合用来存放图的结构 14 private Map<String, List<String>> graphMap=new HashMap<String, List<String>>(); 15 //建立无向图的模型 16 // 图结构如下 17 // 1 18 // / \ 19 // 2 3 20 // / \ / \ 21 // 4 5 6 7 22 // \ | / \ / 23 // 8 9 24 public void initGraph() { 25 /** 26 * 初始化图结构,将每个图节点为key,它的相邻节点以list为value的形式存放到map中 27 */ 28 graphMap.put("1",Arrays.asList("2","3")); 29 graphMap.put("2",Arrays.asList("1","4","5")); 30 graphMap.put("3",Arrays.asList("1","6","7")); 31 graphMap.put("4",Arrays.asList("2","8")); 32 graphMap.put("5",Arrays.asList("2","8")); 33 graphMap.put("6",Arrays.asList("3","8","9")); 34 graphMap.put("7",Arrays.asList("3","9")); 35 graphMap.put("8",Arrays.asList("4","5","6")); 36 graphMap.put("9",Arrays.asList("6","7")); 37 } 38 //用来记录节点是否被访问过 39 private Map<String, Boolean> status=new HashMap<String,Boolean>(); 40 //创建一个队列用来进行宽度优先遍历 41 private Queue<String> queue =new LinkedList<String>(); 42 public void BreadthFS(String startPoint) { 43 //将图的起始点入队 44 queue.offer(startPoint); 45 status.put(startPoint, true); 46 while(!queue.isEmpty()) { 47 //将队首的元素出队 48 String tempPoint =queue.poll(); 49 System.out.print(tempPoint+"-"); 50 //遍历之后的节点,将其状态改为false 51 status.put(tempPoint, false); 52 //遍历该节点邻接的节点 53 for (String point : graphMap.get(tempPoint)) { 54 //如果该节点被访问过,则不入队 55 //getOrDefault:当集合中不存在该key,或者该key的值为null时则默认值为true 56 if(status.getOrDefault(point, true)){ 57 //如果队列中已经存在了该节点,则不再次入队 58 if(!queue.contains(point)) { 59 queue.offer(point); 60 } 61 } 62 } 63 } 64 } 65 public void depthFS(String startPoint) { 66 //建立一个栈用来进行深度优先遍历 67 Stack<String> stack=new Stack<String>(); 68 //用来记录栈中元素的状态 69 Map<String, Boolean> status=new HashMap<String,Boolean>(); 70 //将起始的点入栈 71 stack.push(startPoint); 72 while (!stack.isEmpty()) { 73 //-----------显示栈内的数据情况---------------- 74 System.out.print("\t"); 75 for (String string : stack) { 76 System.out.print(string); 77 if(!string.equals(stack.lastElement())){ 78 System.out.print("->"); 79 } 80 } 81 System.out.println(); 82 //--------------------------- 83 String tempPoint =stack.pop();//出栈 84 85 //出栈后的元素标记为已遍历(false) 86 status.put(tempPoint, false); 87 //打印出栈顺序 88 System.out.print(tempPoint); 89 for (String point : graphMap.get(tempPoint)) { 90 //getOrDefault:当集合中不存在该key,或者该key的值为null时则默认值为true 91 if(status.getOrDefault(point, true)) { 92 //如果包含这个栈中没有这个元素-->入栈 93 //有这个元素,先删除栈中的该元素,再入栈。 94 if(!stack.contains(point)) { 95 stack.push(point); 96 }else { 97 stack.remove(point); 98 stack.push(point); 99 } 100 } 101 } 102 } 103 } 104 //用递归来实现无向图的深度优先遍历 105 public void depthFSwithRecusive(String StartPoint) { 106 if(status.getOrDefault(StartPoint,true)) { 107 System.out.print(StartPoint+"-"); 108 status.put(StartPoint, false); 109 } 110 for (String point : graphMap.get(StartPoint)) { 111 if(status.getOrDefault(point,true)) { 112 depthFSwithRecusive(point); 113 } 114 } 115 } 116 }
测试代码:
1 @org.junit.Test 2 public void graphBFS() { 3 Graph graph=new Graph(); 4 graph.initGraph(); 5 graph.BreadthFS("1"); 6 } 7 @org.junit.Test 8 public void graphDFS() { 9 Graph graph=new Graph(); 10 graph.initGraph(); 11 graph.depthFS("1"); 12 }
深度优先遍历的运行结果:(最左边为 出栈顺序,右边是栈内信息的打印)
深度优先遍历的运行结果: