(十五)图的广度优先遍历BFS及最短路径

类似于一个分层搜索的过程,广度优先遍历需要使用一个队列以保持访问过的结点的顺序,以便按这个顺序来访问这些结点的邻接结点。

具体算法表述如下:

  1. 访问初始结点v并标记结点v为已访问。
  2. 结点v入队列
  3. 当队列非空时,继续执行,否则算法结束。
  4. 出队列,取得队头结点u。
  5. 查找结点u的第一个邻接结点w。
  6. 若结点u的邻接结点w不存在,则转到步骤3;否则循环执行以下三个步骤:
    1). 若结点w尚未被访问,则访问结点w并标记为已访问。
    2). 结点w入队列
    3). 查找结点u的继w邻接结点后的下一个邻接结点w,转到步骤6。

如下图,其广度优先算法的遍历顺序为:1->2->3->4->5->6->7->8

public class a {
	private Map<String, List<String>> graph = new HashMap<String, List<String>>();
	 /**
     * 初始化图数据:使用邻居表来表示图数据。
     */
    public void initGraphData() {
//        图结构如下
//          1
//        /   \
//       2     3
//      / \   / \
//     4  5  6  7
//      \ | / \ /
//        8    9
        graph.put("1", Arrays.asList("2", "3")); //public static <T> List<T> asList(T... a) 例:List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
        graph.put("2", Arrays.asList("1", "4", "5"));
        graph.put("3", Arrays.asList("1", "6", "7"));
        graph.put("4", Arrays.asList("2", "8"));
        graph.put("5", Arrays.asList("2", "8"));
        graph.put("6", Arrays.asList("3", "8", "9"));
        graph.put("7", Arrays.asList("3", "9"));
        graph.put("8", Arrays.asList("4", "5", "6"));
        graph.put("9", Arrays.asList("6", "7"));
    }
    
    /**
     * 宽度优先搜索(BFS, Breadth First Search)
     * BFS使用队列(queue)来实施算法过程
     */
    
    /*
     Queue是个接口 LinkedList:是实现类  是一个双向链表
                链表的优势:
     ①随机访问效率低:对数据的索引需要从链表头开始遍历()
     ②插入元素:无需对数据移动
     
     linkedList:特有的方法 getFirst()、addFirst;getLast()、addLast();removeFirst()、removeLast()
                 
     */
    private Queue<String> queue = new LinkedList<String>(); 
    
    //因为序列是不带重复元素的,所以可以用map来标记是否访问过
    private Map<String, Boolean> status = new HashMap<String, Boolean>();

    /**
     * 开始点
     *
     * @param startPoint
     */
    public void BFSSearch(String startPoint) {
        //1.把起始点放入queue;
        queue.add(startPoint);
        status.put(startPoint, false);
        bfsLoop();
    }

    private void bfsLoop() {
        //  1) 从queue中取出队列头的点;更新状态为已经遍历。
        String currentQueueHeader = queue.poll(); //出队 poll:获取并移除
        status.put(currentQueueHeader, true);
        System.out.println(currentQueueHeader);
        //  2) 找出与此点邻接的且尚未遍历的点,进行标记,然后全部放入queue中。
        List<String> neighborPoints = graph.get(currentQueueHeader);
        for (String poinit : neighborPoints) {
        	//getOrDefault(Object key, V defaultValue) Returns the value to which the specified key is mapped, or defaultValue if this map contains no mapping for the key.
            if (!status.getOrDefault(poinit, false)) { //未被遍历
                if (queue.contains(poinit)) continue;
                queue.add(poinit);
                status.put(poinit, false);
            }
        }
        if (!queue.isEmpty()) {  //如果队列不为空继续遍历
            bfsLoop();
        }
    }

    
public static void main(String [] args)
  {
	
	a test = new a();
    test.initGraphData();
//    test.BFSSearch("1");
    test.BFSSearch("2");
   
  }

广度优先遍历找最短路径

只要将bfsloop简单修改即可

每个节点node的distance都是node距离起始点start的最短距离.

 private void bfsLoop() {
    	LinkedList<Integer> distq = new LinkedList<Integer>();   
    	distq.push(0);
    	while(!queue.isEmpty())
    	{
        
        String currentQueueHeader = queue.poll(); //出队 poll:获取并移除
        status.put(currentQueueHeader, true);
        System.out.println("当前节点:"+currentQueueHeader);
        
        List<String> neighborPoints = graph.get(currentQueueHeader);
        int d=distq.poll();
        for (String poinit : neighborPoints) {
        	distq.push(d+1);//说明要访问邻接的顶点
        	
            if (!status.getOrDefault(poinit, false)) { 
            	System.out.println("1--"+poinit+"的距离为"+distq.peek());
                if (queue.contains(poinit)) continue;
                queue.add(poinit);
                status.put(poinit, false);
            }
        }
    	}
    }

 

posted @ 2019-06-12 14:45  测试开发分享站  阅读(562)  评论(0编辑  收藏  举报