图——深度优先和广度优先
一.图的遍历
图的遍历,即是对结点的访问,从图中的任一顶点出发,对图中的所有顶点访问一次且只访问一次。一个图有那么多个结点,如何遍历这些结点,需要特定策略,一般有两种访问策略:
1.深度优先遍历:体现了栈的思想,假设初始状态是图中所有顶点未曾被访问,则深度优先搜索可从图中某个顶点发v 出发,访问此顶点,然后依次从v 的未被访问的邻接点出发深度优先遍历图,直至图中所有和v 有路径相通的顶点都被访问到;若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止,类似于树的先根遍历,是树的先根遍历的推广;
2.广度优先遍历:体现了队列的思想 ,假设从图中某顶点v 出发,在访问了v 之后依次访问v 的各个未曾访问过和邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问,直至图中所有已被访问的顶点的邻接点都被访问到。若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。换句话说,广度优先搜索遍历图的过程中以v 为起始点,由近至远,依次访问和v 有路径相通且路径长度为1,2,…的顶点,类似于树的按层次遍历;
二.图的结构模型
1.邻接矩阵:使用二维数组实现,空间上会造成浪费。
2.领接表:使用数组+链表实现,顶点用一个一维数组存储,当然,顶点也可以用单链表来存储,不过,数组可以较容易的读取顶点的信息,每个顶点vi的所有邻接点构成一个线性表,由于邻接点的个数不定,所以,用单链表存储。
3.十字链表:在有向图中,对于邻接表来说,计算顶点的入度是不方便的,因此可修改调整节点结构,构建十字链表,方便计算顶点的出度和入度。
三.图的遍历实现
1.深度优先
(1)访问顶点v;
(2)从v的未被访问的邻接点中选取一个顶点w,从w出发进行深度优先遍历;
(3)重复上述两步,直至图中所有和v有路径相通的顶点都被访问到。
①递归实现
(1)访问顶点v;visited[v]=1;//算法执行前visited[n]=0
(2)w=顶点v的第一个邻接点;
(3)while(w存在)
if(w未被访问)
从顶点w出发递归执行该算法;
w=顶点v的下一个邻接点;
②栈实现
(1)栈S初始化;visited[n]初始化为0;
(2)访问顶点v;visited[v]=1;顶点v入栈S
(3)while(栈S非空)
x=栈S的顶元素(出栈);
while(x的邻接点w)
if(w存在并未被访问)
访问w;visited[w]=1;
w进栈;
2.广度优先
队列实现:与栈实现基本相同,只是使用的是队列。
四.代码示例
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
import java.util.Stack;
public class graphTraverse {
public static void bfsMethod(int[][] adjMatrix, int sourceNode){
//利用队列
Queue<Integer> queue = new LinkedList<Integer>();
int numOfNodes = adjMatrix[sourceNode].length;
int[] isVisited = new int[numOfNodes];//没访问过的初始化为0
isVisited[sourceNode] = 1;
queue.add(sourceNode);
int i = 0;//index表示
int element = 0;//当前元素
while(!queue.isEmpty()){
element = queue.remove();
System.out.print(element+" ");
i = 0;
while(i < numOfNodes){
if(adjMatrix[element][i] == 1 && isVisited[i] == 0){
queue.add(i);//按照最先遍历到的1进入队列为原则, 如果有好几个1在一行,也就是一个顶点与多个顶点相连
isVisited[i] = 1;
}
i++;
}
}
}
public static void dfsMethod(int [][] adjMatrix, int sourceNode){
//利用栈,因为需要回溯,弹出一个节点的同时把它的儿子压入栈中,把儿子弹出来时,把孙子压入栈中,所以就可以按深度了
Stack<Integer> stack = new Stack<Integer>();
int numOfNodes = adjMatrix[sourceNode].length;
int[] isVisited = new int[numOfNodes];
stack.push(sourceNode);
isVisited[sourceNode] = 1;
int element = 0;
while(!stack.isEmpty()){
element = stack.pop();
System.out.println(element + " ");
for(int i = 0; i < numOfNodes; i++){
if(adjMatrix[element][i] == 1 && isVisited[i] == 0){
stack.push(i);
isVisited[i] = 1;
}
}
}
}
public static void main(String[] args){
int numOfNodes = 0;
int sourceNode = 0;//设置哪一个点为起始点
Scanner scanner = new Scanner(System.in);
System.out.println("请输入图的节点总数:");
numOfNodes = scanner.nextInt();
int[][] adjMatrix = new int[numOfNodes][numOfNodes];
System.out.println("请输入图的临接矩阵:");
for(int i = 0; i < numOfNodes; i++){
for(int j = 0; j < numOfNodes; j++){
adjMatrix[i][j] = scanner.nextInt();
}
}
System.out.println("请输入图开始遍历的起点Source(从0开始编号):");
sourceNode = scanner.nextInt();
System.out.println("图的广度优先遍历(BFS)结果为(从0开始编号):");
bfsMethod(adjMatrix, sourceNode);
System.out.println("\n图的深度优先遍历(DFS)结果为(从0开始编号):");
dfsMethod(adjMatrix, sourceNode);
scanner.close();
}
}
浙公网安备 33010602011771号