BFS
BFS(Breadth First Search)广度优先搜索,类似于二叉树的层序遍历,基本思想:首先访问起始顶点v,接着由v出发,依次访问v的各个未访问过的邻接顶点w1,w2,…,wn,然后再依次访问w1,w2,…,wn所有未被访问过的邻接顶点。。。类似的思想还将应用于Dijkstra单源最短路径算法和Prim最小生成树算法。
广度优先搜索是一种分层查找过程,不像深度优先有往回退的情况,所有它不是一个递归算法。通过借助队列,来记忆正在访问的顶点的下一层顶点。
伪代码
bool visited[图的点数];//访问标记数组,访问过为false
void BFS(Graph G){
visit(0);//访问起始节点
visited[0]=true;
Queue queue;
queue.add(0);//顶点i入队
while(!q.isEmpty()){
Node node = q.poll();//出队
for(…){
if (!visited[node邻接点])
//将node的未访问过的邻接节点入队
}
}
}
因为是伪代码,表达算法思想,不符合语法规范。很多涉及到BFS算法思想的都是基于这个上面进行修改。
BFS算法求单元最短路径
最短路径表示图中从u到v最短的边数,这是由BFS算法总是按照距离由近及远来遍历顶点的性质决定的。
void BFSMinDistance(Graph G,int u){ int dst[] = new int[n]; for (int i=0;i<n;i++) dst[i]=-1;//dst[i]表示从u到i的最短路径,-1表示不可达 dst[u]=0; Queue q; q.add(u)//将u入队 while(!q.isEmpty()){ q.poll(); for(...){ if (dst[i]!=-1)//!=-1表示可达之前访问过,如果是带权路径,需要计算比较替换 //将node的未访问过的邻接节点入队 } } }
最短路径例题
网易2017秋招笔试题,跳石板,每块石板的编号从1、2、3…开始编号,在石板上,只能往前跳编号N的约束步(不包含1和N),问从N跳到M最少跳几步(4<=N<=M<=100000)。
分析:
从N跳到M,就是找从N到M的最短路径,例如N的约束包含a,b,c等,那么N到N+a,N+b,N+c的步数就是1,在从N+a往后继续这样跳,步数+1,以此类推。
public static void main(String[] args){ Scanner sc = new Scanner(System.in); int N = sc.nextInt(); int M = sc.nextInt(); //dst表示到达i位置的步数,-1表示不可达 int[] dst = new int[M+1]; for (int i=N;i<=M;i++){ dst[i]=-1;//初始化 } dst[N]=0;//从N开始,dst[N]为0步 for (int i=N;i<=M;i++){ if (dst[i]==-1)//如果该位置不可达则直接跳过 continue; for (int j=2;j*2<=i;j++){ if (i%j==0){//寻找约束,也就是跳的步数 if (i+j<=M&&dst[i+j]==-1)//如果跳的位置<=M并且该位置未到过 dst[i+j]=dst[i]+1;//步数在调过来的基础上+1 } } } System.out.println(dst[M]); }
这里没有使用队列,因为按照石板的编号就能依次遍历,不可达的直接跳过,直到M。
DFS
DFS(Depth First Search)深度优先搜索,类似于树的先序遍历。这种搜索算法是尽可能“深”地搜索图。基本思想:首先访问图中起始点v,然后访问与v邻接并且未被访问的顶点w1,再访问与w1邻接未被访问的顶点w2,。。。重复该过程。当不能继续访问时,依次退回到最近被访问的顶点,再访问该顶点未被访问的邻接点。
伪代码
很明显,该算法需要借助栈或者通过递归实现。
//通过递归实现 void DFS(Graph G,int v){ visit(v); visited[v]=true; while (v有邻接点w){ if (!visited[w]) DFS; } } //通过栈 void DFS(Graph G,int v){ Stack stack; stack.push(v); while (!stack.isEmpty()){ node=stack.pop(); visit(node); visited[node]=true; while (node有邻接点w){ if (!visited[w]) stack.push(w); } } }
图的遍历算法可以用来判断图的连通性。