图的遍历就是从图中某个顶点出发,按某种方法对图中所有顶点访问且仅访问一次。
图的遍历算法是求解图的连通性问题、拓扑排序和求关键路径等算法的基础,也可以用作网页的爬虫技术,
深度优先遍历(depth-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 }
深度优先遍历的运行结果:(最左边为 出栈顺序,右边是栈内信息的打印)
深度优先遍历的运行结果: