一、图的概念
相比栈、队列、二叉树、图是一种更复杂的数据结构。图由节点和边组成
二、用java实现图
定义节点
@Setter
@Getter
public class GraphNode<T> {
private T data;
private List<GraphNode<T>> neighbourNodeList;
private boolean visited;
public GraphNode(T data){
this.data = data;
neighbourNodeList = new ArrayList<>();
}
@Override
public String toString() {
if(data == null){
return null;
}
return data.toString();
}
}
定义边
边可以使用节点之间的引用关系表示。
public class Graph<T> {
/**
* 画不出来图的结构了...
* 1
* / \
* 2 3
* / / \ / \ \
* 4 - 5 - 6 7 8
* / \
* 9 - 10
*/
private GraphNode<Integer> buildGraph(){
GraphNode<Integer> node1 = new GraphNode<>(1);
GraphNode<Integer> node2 = new GraphNode<>(2);
GraphNode<Integer> node3 = new GraphNode<>(3);
GraphNode<Integer> node4 = new GraphNode<>(4);
GraphNode<Integer> node5 = new GraphNode<>(5);
GraphNode<Integer> node6 = new GraphNode<>(6);
GraphNode<Integer> node7 = new GraphNode<>(7);
GraphNode<Integer> node8 = new GraphNode<>(8);
GraphNode<Integer> node9 = new GraphNode<>(9);
GraphNode<Integer> node10 = new GraphNode<>(10);
node1.getNeighbourNodeList().add(node2);
node1.getNeighbourNodeList().add(node3);
node2.getNeighbourNodeList().add(node4);
node2.getNeighbourNodeList().add(node5);
node2.getNeighbourNodeList().add(node6);
node3.getNeighbourNodeList().add(node1);
node3.getNeighbourNodeList().add(node6);
node3.getNeighbourNodeList().add(node7);
node3.getNeighbourNodeList().add(node8);
node4.getNeighbourNodeList().add(node2);
node4.getNeighbourNodeList().add(node5);
node5.getNeighbourNodeList().add(node2);
node5.getNeighbourNodeList().add(node4);
node5.getNeighbourNodeList().add(node6);
node6.getNeighbourNodeList().add(node2);
node6.getNeighbourNodeList().add(node5);
node6.getNeighbourNodeList().add(node3);
node6.getNeighbourNodeList().add(node8);
node6.getNeighbourNodeList().add(node9);
node6.getNeighbourNodeList().add(node10);
node7.getNeighbourNodeList().add(node3);
node8.getNeighbourNodeList().add(node3);
node8.getNeighbourNodeList().add(node6);
node8.getNeighbourNodeList().add(node9);
node9.getNeighbourNodeList().add(node6);
node9.getNeighbourNodeList().add(node8);
node9.getNeighbourNodeList().add(node10);
node10.getNeighbourNodeList().add(node6);
node10.getNeighbourNodeList().add(node9);
return node1;
}
}
三、图的遍历
遍历的类型
图的遍历类似树的遍历分为两种。分别为广度优先遍历和深度优先遍历。
广度优先遍历
广度优先遍历是指从起始节点开始优先遍历离自己近的节点,近的节点遍历完之后,再遍历次近的节点。以此类推,直到所有的节点都被访问到。
基于队列实现广度优先遍历
/**
* 依赖队列实现广度优先遍历
*/
public void breadthFirstSearchByQueue(GraphNode<T> node){
//队列
Queue<GraphNode<T>> nodeQueue = new ArrayDeque<>();
nodeQueue.offer(node);
while (!nodeQueue.isEmpty()){
GraphNode<T> nodeFromQueue = nodeQueue.poll();
//如果在这里标记已处理的话,后面入队的元素可能会是已经被访问过得
//handleNode(nodeFromQueue);
List<GraphNode<T>> neighbourNodeList = nodeFromQueue.getNeighbourNodeList();
if(neighbourNodeList != null){
for(GraphNode<T> neighbourNode : neighbourNodeList){
if(!neighbourNode.isVisited()){
//处理之后再入队,可以保证每个入队的元素都是已经被处理过的
handleNode(neighbourNode);
nodeQueue.offer(neighbourNode);
}
}
}
}
}
深度优先遍历
深度优先遍历指从起始节点开始优先遍历路径长的节点,直到节点无邻居节点
基于递归实现深度优先遍历
/**
* 深度优先,递归方式实现
*/
public void deepFirstSearchByRecursive(GraphNode<T> node){
handleNode(node);
List<GraphNode<T>> neighbourNodeList = node.getNeighbourNodeList();
if(neighbourNodeList != null){
for(GraphNode<T> nodeItem : neighbourNodeList){
if(!nodeItem.isVisited()){
deepFirstSearchByRecursive(nodeItem);
}
}
}
}
基于栈实现深度优先遍历
/**
* 基于栈实现深度优先遍历
*/
public void deepFirstSearchByStack(GraphNode<T> graphNode){
Stack<GraphNode<T>> stack = new Stack<>();
stack.push(graphNode);
while (!stack.isEmpty()){
GraphNode<T> node = stack.pop();
if(node.getNeighbourNodeList() != null){
for (GraphNode<T> neighbourNode : node.getNeighbourNodeList()){
if(!neighbourNode.isVisited()){
handleNode(neighbourNode);
stack.push(neighbourNode);
}
}
}
}
}