图的遍历是指从图中某一顶点出发,访遍图中其余顶点,且使每一个顶点仅被访问一次。
一、深度优先遍历(Depth First Search)
假设给定图G的初态是所有顶点均未曾访问过。在G中任选一顶点v为初始出发点(源点),则深度优先遍历可定义如下:首先访问出发点v,并将其标记为已访问过;然后依次从v出发搜索v的每个邻接点w。若w未曾访问过,则以w为新的出发点继续进行深度优先遍历,直至图中所有和源点v有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止。若此时图中仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复上述过程,直至图中所有顶点均已被访问为止。
深度优先遍历是一个递归的过程,类似于树的前序遍历,它的策略是尽可能的对纵深方向进行搜索。
有向网图邻接矩阵DPS代码示例:
//邻接矩阵DFS算法
private static void DFS(AdjacencyMatrix.Matrix matrix, int i){
int j;
visited[i] = true;
System.out.print(matrix.getVexs()[i]);
for (j = 0; j < matrix.getVerNum(); j++){
if(matrix.getArc()[i][j] > 0 && ! visited[j]&&matrix.getArc()[i][j] != 65535 )
DFS(matrix, j);
}
}
//邻接矩阵深度遍历操作
private static void DFSTraverse(){
adjacencyMatrix.CreateMGraph();
mGraph = adjacencyMatrix.matrix; //图的矩阵表示
int i;
for (i = 0; i < mGraph.getVerNum(); i++){
visited[i] = false; //是否访问的标志
}
for(i = 0; i < mGraph.getVerNum(); i++){
if(! visited[i]){
DFS(mGraph, i);
}
}
}
有向网图邻接表DFS代码示例:
//邻接表DFS算法
private static void DFS(AdjacencyList.AdjacencyGraph graph, int i){
AdjacencyList.EdgeNode edgeNode;
visited[i] = true;
System.out.print(graph.getVertexNodes()[i].getData());
edgeNode = graph.getVertexNodes()[i].getFirstEdge();
while (edgeNode != null){
if(!visited[edgeNode.getAdjvex()]){
DFS(graph, edgeNode.getAdjvex());
}
edgeNode = edgeNode.getNext();
}
}
//邻接表深度遍历操作
private static void DFSTraverse(){
adjacencyList.CreateList();
lGraph = adjacencyList.adjacencyGraph;
int i;
for(i = 0; i < lGraph.getVertexNum(); i++)
visited[i] = false;
for (i = 0; i < lGraph.getVertexNum(); i++){
if(! visited[i]){
DFS(lGraph, i);
}
}
}
对比两种存储结构的DFS算法,邻接矩阵是二维数组,时间复杂度为O(n^2^),邻接表的时间复杂度为O(n+e),e为边数,当点多边少时,邻接表更优。
广度优先遍历(Breadth First Search)
1、从图中某个顶点V0出发,并访问此顶点;
2、从V0出发,访问V0的各个未曾访问的邻接点W1,W2,…,Wk;然后,依次从W1,W2,…,Wk出发访问各自未被访问的邻接点;
3、重复步骤2,直到全部顶点都被访问为止。
广度优先遍历类似于树的层序遍历。树的层序遍历是通过队列实现的,图也同理。
邻接矩阵DFS算法:
//邻接矩阵BFS算法
private static void BFSTraverse(){
int i,j;
Queue<Integer> queue = new LinkedList<>();
for(i = 0; i < mGraph.getVerNum(); i++)
visited[i] = false;
for (i = 0; i < mGraph.getVerNum(); i++){
if(! visited[i]){
visited[i] = true;
System.out.print(mGraph.getVexs()[i]);
queue.add(i);
while (! queue.isEmpty()){
queue.poll();
for (j = 0; j < mGraph.getVerNum(); j++){
if(mGraph.getArc()[i][j] > 0 && ! visited[j] && mGraph.getArc()[i][j] != 65535){
visited[j] = true;
System.out.print(mGraph.getVexs()[j]);
queue.poll();
}
}
}
}
}
}
邻接表DFS算法:
//邻接表BFS算法
private static void BFSTraverse(){
int i;
AdjacencyList.EdgeNode edgeNode;
Queue<Integer> queue = new LinkedList<>();
for(i = 0; i < lGraph.getVertexNum(); i++){
visited[i] = false;
}
for (i = 0; i < lGraph.getVertexNum(); i++){
if(! visited[i]){
visited[i] = true;
System.out.print(lGraph.getVertexNodes()[i].getData());
queue.add(i);
while (! queue.isEmpty()){
queue.poll();
edgeNode = lGraph.getVertexNodes()[i].getFirstEdge();
while (edgeNode != null) {
if(! visited[edgeNode.getAdjvex()]) {
visited[edgeNode.getAdjvex()] = true;
System.out.print(lGraph.getVertexNodes()[edgeNode.getAdjvex()].getData());
queue.poll();
}
edgeNode = edgeNode.getNext();
}
}
}
}
}
深度优先适合目标比较明确,以找到目标为主要目的情况,广度优先更适合在不断扩大遍历范围时找到相对最优解的情况。