【校招VIP】数据结构--图

05月11日 收藏 0 评论 2 java开发

【校招VIP】数据结构--图

转载声明:文章来源https://blog.csdn.net/hehuanchun0311/article/details/80168109

一、图的基本概念

线性表和树两类数据结构,线性表中的元素是“一对一”的关系,树中的元素是“一对多”的关系,本章所述的图结构中的元素则是“多对多”的关系。

图(Graph)是一种复杂的非线性结构,在图结构中,每个元素都可以有零个或多个前驱,也可以有零个或多个后继,也就是说,元素之间的关系是任意的。

无向图:
无向图是由顶点和边构成。

有向图:
有向图是由顶点和有向边构成。

完全图:
如果任意两个顶点之间都存在边叫完全图,有向的边叫有向完全图。如果无重复的边或者顶点到自身的边叫简单图。

二、图的节点表示

/**
* 无向简单图的节点
* @author hoaven
*/
public class GraphNode<T> {
T data;
List<GraphNode<T>> neighborList;
boolean visited;

public GraphNode(T data){
this.data = data;
neighborList = new ArrayList<GraphNode<T>>();
visited = false;
}

public boolean equals(GraphNode<T> node){
return this.data.equals(node.data);
}

/**
* 还原图中所有节点为未访问
*/
public void restoreVisited(){
restoreVisited(this);
}

/**
* 还原node的图所有节点为未访问
* @param node
*/
private void restoreVisited(GraphNode<T> node){
if(node.visited){
node.visited = false;
}

List<GraphNode<T>> neighbors = node.neighborList;
for(int i = 0; i < neighbors.size(); i++){
restoreVisited(neighbors.get(i));
}

}
}

三、图的深度优先和广度优先搜索

1、深度优先

1.1、介绍

图的深度优先搜索(Depth First Search),和树的先序遍历比较类似。

思路:假设初始状态是图中所有顶点均未被访问,则从某个顶点v出发,首先访问该顶点,然后依次从它的各个未被访问的邻接点出发深度优先搜索遍历图,直至图中所有和v有路径相通的顶点都被访问到。 若此时尚有其他顶点未被访问到,则另选一个未被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。显然,深度优先搜索是一个递归的过程。

对上面的图G1进行深度优先遍历,从顶点A开始。

第1步:访问A。
第2步:访问(A的邻接点)C。在第1步访问A之后,接下来应该访问的是A的邻接点,即”C,D,F”中的一个。但在本文的实现中,顶点ABCDEFG是按照顺序存储,C在”D和F”的前面,因此,先访问C。
第3步:访问(C的邻接点)B。在第2步访问C之后,接下来应该访问C的邻接点,即”B和D”中一个(A已经被访问过,就不算在内)。而由于B在D之前,先访问B。
第4步:访问(C的邻接点)D。
第5步:访问(A的邻接点)F。
第6步:访问(F的邻接点)G。
第7步:访问(G的邻接点)E。
访问顺序是:A -> C -> B -> D -> F -> G -> E

1.3、无向图深度优先搜索图解

对上面的图G2进行深度优先遍历,从顶点A开始。

访问顺序是:A -> B -> C -> E -> D -> F -> G

2、广度优先

2.1、介绍

从图中某顶点v出发,在访问了v之后依次访问v的各个未曾访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使得“先被访问的顶点的邻接点先于后被访问的顶点的邻接点被访问,直至图中所有已被访问的顶点的邻接点都被访问到。如果此时图中尚有顶点未被访问,则需要另选一个未曾被访问过的顶点作为新的起始点,重复上述过程,直至图中所有顶点都被访问到为止。换句话说,广度优先搜索遍历图的过程是以v为起点,由近至远。

2.2、无向图广度优先搜索图解

访问顺序是:A -> C -> D -> F -> B -> G -> E

2.3、有向图广度优先搜索图解

访问顺序是:A -> B -> C -> E -> F -> D -> G

3、实现

/**
* 图的广度优先搜索和深度优先搜索实现
*
* @author hoaven
* @see GraphNode
*/
public class GraphSearch<T> {

public StringBuffer searchPathDFS = new StringBuffer();
public StringBuffer searchPathBFS = new StringBuffer();

/**
* 深度优先搜索实现
*
* @param root
*/
public void searchDFS(GraphNode<T> root) {
if (root == null) {
return;
}

// visited root
if (searchPathDFS.length() > 0) {
searchPathDFS.append("->");
}
searchPathDFS.append(root.data.toString());
root.visited = true;

for (GraphNode<T> node : root.neighborList) {
if (!node.visited) {
searchDFS(node);
}
}
}

/**
* 广度优先搜索实现,使用队列
*
* @param root
*/
public void searchBFS(GraphNode<T> root) {
IQueue<GraphNode<T>> queue = new Queue<GraphNode<T>>();

// visited root
if (searchPathBFS.length() > 0) {
searchPathBFS.append("->");
}
searchPathBFS.append(root.data.toString());
root.visited = true;

// 加到队列队尾
queue.enqueue(root);

while (!queue.isEmpty()) {
GraphNode<T> r = queue.dequeue();
for (GraphNode<T> node : r.neighborList) {
if (!node.visited) {
searchPathBFS.append("->");
searchPathBFS.append(node.data.toString());
node.visited = true;

queue.enqueue(node);
}
}
}
}
}

//测试用例
/**
* GraphSearch测试
* @author hoaven
* @see GraphNode
* @see GraphSearch
*/
public class GraphSearchTest {
GraphNode<Integer> node1;
GraphNode<Integer> node2;
GraphNode<Integer> node3;
GraphNode<Integer> node4;
GraphNode<Integer> node5;
GraphNode<Integer> node6;
GraphNode<Integer> node7;
GraphNode<Integer> node8;
GraphNode<Integer> node9;
GraphNode<Integer> node10;

@Before
public void before(){
node1 = new GraphNode<Integer>(1);
node2 = new GraphNode<Integer>(2);
node3 = new GraphNode<Integer>(3);
node4 = new GraphNode<Integer>(4);
node5 = new GraphNode<Integer>(5);
node6 = new GraphNode<Integer>(6);
node7 = new GraphNode<Integer>(7);
node8 = new GraphNode<Integer>(8);
node9 = new GraphNode<Integer>(9);
node10 = new GraphNode<Integer>(10);

node1.neighborList.add(node2);
node1.neighborList.add(node3);

node2.neighborList.add(node4);
node2.neighborList.add(node5);
node2.neighborList.add(node6);

node3.neighborList.add(node1);
node3.neighborList.add(node6);
node3.neighborList.add(node7);
node3.neighborList.add(node8);

node4.neighborList.add(node2);
node4.neighborList.add(node5);

node5.neighborList.add(node2);
node5.neighborList.add(node4);
node5.neighborList.add(node6);

node6.neighborList.add(node2);
node6.neighborList.add(node5);
node6.neighborList.add(node3);
node6.neighborList.add(node8);
node6.neighborList.add(node9);
node6.neighborList.add(node10);

node7.neighborList.add(node3);

node8.neighborList.add(node3);
node8.neighborList.add(node6);
node8.neighborList.add(node9);

node9.neighborList.add(node6);
node9.neighborList.add(node8);
node9.neighborList.add(node10);

node10.neighborList.add(node6);
node10.neighborList.add(node9);
}

@Test
public void searchDFSTest(){
GraphSearch<Integer> graphSearch = new GraphSearch<Integer>();
graphSearch.searchDFS(node1);

String expectedSearchPath = "1->2->4->5->6->3->7->8->9->10";
Assert.assertEquals(expectedSearchPath, graphSearch.searchPathDFS.toString());
}

@Test
public void searchBFSTest(){
GraphSearch<Integer> graphSearch = new GraphSearch<Integer>();
graphSearch.searchBFS(node1);

String expectedSearchPath = "1->2->3->4->5->6->7->8->9->10";
Assert.assertEquals(expectedSearchPath, graphSearch.searchPathBFS.toString());
}
}


C 2条回复 评论
我爱陈萍萍

是道好题,会了这道就能举一反三

发表于 2023-02-04 21:00:00
0 0
卡卡卡

看这个冲刺面试

发表于 2022-12-13 21:00:00
0 0