广度优先搜索BFS及java实现

2022-03-28 20:20:56 浏览数 (1)

广度优先搜索是图里面一种基础的搜索算法,英文简写BFS(breadth First Search),广度优先搜索能够搜索到源节点S到图中其他节点的最短距离,该方法适用于无权有向或者无权无向图中,

广度优先搜索采用的方式类似二叉树的层次遍历,比如对节点V3来说,V1、V5属于第一层,V4、V6、V2属于第二层,从V3到V5的最短距离是V3->V5这条边,而不是从V3->V1->V4->V5,好比人类关系一样,比如A、B、C、D、E五人,A认识B,B认识C,C认识E,于此同时A认识D,D也认识E,比如A需要找E办点事,正常的逻辑是通过D结实E,这样只需经过两道关系,通过B的话则需要经过三道关系,广度优先搜索类似,按照距离源节点的远近来进行检索。

下面给出广度优先搜索的java实现:

代码语言:javascript复制
/**
**图的节点类
**/
public class Vertex {
    //该节点颜色,当color为VertexColor.WHITE时表名该节点没有被路由过,为其他颜色说明已经被使用过,后续路径的遍历就不要再遍历这个节点了,前面已经提到了广度优先搜索的层次搜索概念,最先被搜索到的是与源节点关系最近的路径
	private VertexColor color;
	//源节点到该顶点的距离
	private int distance;
	//前驱节点
	private Vertex pre;
	//该顶点的连接队列
	private List<Vertex> adjList;
	//统计该节点在图顶点数组下标,对广度搜索非必要属性,仅用于统计使用
	private int index ;
	
	public Vertex(int index){
		this.index = index;
		adjList = new LinkedList<>();
		this.color = VertexColor.WHITE;
		this.pre = null;
		this.distance = Integer.MAX_VALUE;
	}
	
	//添加邻接矩阵点
	public void addVertex(Vertex v){
		this.adjList.add(v);
	}
	
	public VertexColor getColor() {
		return color;
	}
	public void setColor(VertexColor color) {
		this.color = color;
	}
	public int getDistance() {
		return distance;
	}
	public void setDistance(int distance) {
		this.distance = distance;
	}
	public Vertex getPre() {
		return pre;
	}
	public void setPre(Vertex pre) {
		this.pre = pre;
	}
	public List<Vertex> getAdjList() {
		return adjList;
	}
	public void setAdjList(List<Vertex> adjList) {
		this.adjList = adjList;
	}
	
	@Override
	public String toString(){
		return String.format("到节点:%d的最短距离为:%d,前驱节点下标为:%d,当前颜色为:%s", index,distance,pre.index,color);
	}
}
代码语言:javascript复制
//顶点颜色
public enum VertexColor {
	WHITE,GRAY,BLACK;
}
代码语言:javascript复制
public class Graph {
	//图中的顶点
	private List<Vertex> vertexes;
	
	public Graph(int len){
		//初始化时指定长度,避免扩容
		vertexes = new ArrayList<>(len);
	}
	
	public void addVertex(Vertex v){
		vertexes.add(v);
	}
	
	public List<Vertex> getVertexes() {
		return vertexes;
	}

	public void setVertexes(List<Vertex> vertexes) {
		this.vertexes = vertexes;
	}
}

上面为基础类,下面为demo代码:

代码语言:javascript复制
	@Test
	public void bfsSearch(){
		Graph g= new Graph(6);
		
		Vertex v1 = new Vertex(1);
		Vertex v2 = new Vertex(2);
		Vertex v3 = new Vertex(3);
		Vertex v4 = new Vertex(4);
		Vertex v5 = new Vertex(5);
		Vertex v6 = new Vertex(6);
		//初始化图的顶点数组
		g.addVertex(v1);
		g.addVertex(v2);
		g.addVertex(v3);
		g.addVertex(v4);
		g.addVertex(v5);
		g.addVertex(v6);
		//初始化邻接矩阵
		v1.addVertex(v2);
		v1.addVertex(v4);
		//
		v2.addVertex(v4);
		//
		v3.addVertex(v1);
		v3.addVertex(v5);
		//
		v4.addVertex(v5);
		v4.addVertex(v6);
		//
		v5.addVertex(v6);
		//查找v3节点到其他节点的最短距离
		println("节点v3到其他节点的最短距离");
		bfs(g,v3);
		//查找v1节点到其他节点的最短距离
		println("节点v1到其他节点的最短距离");
		bfs(g,v1);
	}
	
	public void bfs(Graph g,Vertex s){
		//清空数据
		List<Vertex> vertexList = g.getVertexes();
		for(Vertex v:vertexList){
			v.setColor(VertexColor.WHITE);
			v.setDistance(Integer.MAX_VALUE);
			v.setPre(null);
		}
		//设置源节点数据,自己到自己的最短距离为0
		s.setDistance(0);
		s.setColor(VertexColor.GRAY);
		//LinkedList也是一种队列
		Queue<Vertex> q = new LinkedList<>();
		q.add(s);
		while(!q.isEmpty()){
			//将顶点从队列弹出
			Vertex u = q.remove();
			List<Vertex> list = u.getAdjList();
			for(Vertex v:list){
				if(v.getColor() == VertexColor.WHITE){
					v.setColor(VertexColor.GRAY);
					//设置源节点到该节点的距离,在前驱节点的基础上加1
					v.setDistance(u.getDistance() 1);
					//
					v.setPre(u);
					//将v入队列
					q.add(v);
				}
			}
			//更新u节点颜色
			u.setColor(VertexColor.BLACK);
		}
		//输出源节点到每个节点的最短距离
		for(Vertex v:vertexList){
			if(v == s || v.getDistance() == Integer.MAX_VALUE)
				continue;
			println(v.toString());
		}
	}

输出: 节点v3到其他节点的最短距离 到节点:1的最短距离为:1,前驱节点下标为:3,当前颜色为:BLACK 到节点:2的最短距离为:2,前驱节点下标为:1,当前颜色为:BLACK 到节点:4的最短距离为:2,前驱节点下标为:1,当前颜色为:BLACK 到节点:5的最短距离为:1,前驱节点下标为:3,当前颜色为:BLACK 到节点:6的最短距离为:2,前驱节点下标为:5,当前颜色为:BLACK 节点v1到其他节点的最短距离 到节点:2的最短距离为:1,前驱节点下标为:1,当前颜色为:BLACK 到节点:4的最短距离为:1,前驱节点下标为:1,当前颜色为:BLACK 到节点:5的最短距离为:2,前驱节点下标为:4,当前颜色为:BLACK 到节点:6的最短距离为:2,前驱节点下标为:4,当前颜色为:BLACK

0 人点赞