zoukankan      html  css  js  c++  java
  • 数据结构–图(深度优先遍历和广度优先遍历)(Java)

    数据结构–图(深度优先遍历和广度优先遍历)(Java)

    博客说明

    文章所涉及的资料来自互联网整理和个人总结,意在于个人学习和经验汇总,如有什么地方侵权,请联系本人删除,谢谢!

    图的常用概念

    图是一种数据结构,其中结点可以具有零个或多个相邻元素。两个结点之间的连接称为边。 结点也可以称为顶点。

    • 顶点(vertex)
    • 边(edge)
    • 路径
    • 无向图

    image-20200904124205865

    • 有向图

    image-20200904124318805

    • 带权图

    image-20200904124332489

    图的表示方式

    图的表示方式有两种:二维数组表示(邻接矩阵);链表表示(邻接表)。

    邻接矩阵

    邻接矩阵是表示图形中顶点之间相邻关系的矩阵,对于n个顶点的图而言,矩阵是的row和col表示的是1....n个点。

    image-20200904124501028

    邻接表

    邻接矩阵需要为每个顶点都分配n个边的空间,其实有很多边都是不存在,会造成空间的一定损失

    邻接表的实现只关心存在的边,不关心不存在的边。因此没有空间浪费,邻接表由数组+链表组成

    image-20200904124627030

    代码实现

    package com.guizimo;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.LinkedList;
    
    public class Graph {
    
    	private ArrayList<String> vertexList; 
    	private int[][] edges; 
    	private int numOfEdges; 
    	private boolean[] isVisited;
    	
    	public static void main(String[] args) {
    
    		int n = 8;
    		String Vertexs[] = {"1", "2", "3", "4", "5", "6", "7", "8"};
    		Graph graph = new Graph(n);
    		for(String vertex: Vertexs) {
    			graph.insertVertex(vertex);
    		}
    		
    		//插入图的节点
    		graph.insertEdge(0, 1, 1);
    		graph.insertEdge(0, 2, 1);
    		graph.insertEdge(1, 3, 1);
    		graph.insertEdge(1, 4, 1);
    		graph.insertEdge(3, 7, 1);
    		graph.insertEdge(4, 7, 1);
    		graph.insertEdge(2, 5, 1);
    		graph.insertEdge(2, 6, 1);
    		graph.insertEdge(5, 6, 1);
    
    		//遍历图
    		graph.showGraph();
    		
    		System.out.println("广度优先遍历
    		graph.dfs(); 
    		System.out.println("深度优先遍历
    		graph.bfs();
    		
    	}
    	
    	public Graph(int n) {
    		edges = new int[n][n];
    		vertexList = new ArrayList<String>(n);
    		numOfEdges = 0;
    	}
    	
    
    	public int getFirstNeighbor(int index) {
    		for(int j = 0; j < vertexList.size(); j++) {
    			if(edges[index][j] > 0) {
    				return j;
    			}
    		}
    		return -1;
    	}
    
    	public int getNextNeighbor(int v1, int v2) {
    		for(int j = v2 + 1; j < vertexList.size(); j++) {
    			if(edges[v1][j] > 0) {
    				return j;
    			}
    		}
    		return -1;
    	}
    	
    	//深度优先遍历
    	private void dfs(boolean[] isVisited, int i) {
    		System.out.print(getValueByIndex(i) + "->");
    		isVisited[i] = true;
    		int w = getFirstNeighbor(i);
    		while(w != -1) {
    			if(!isVisited[w]) {
    				dfs(isVisited, w);
    			}
    			w = getNextNeighbor(i, w);
    		}
    		
    	}
    	
    	public void dfs() {
    		isVisited = new boolean[vertexList.size()];
    		for(int i = 0; i < getNumOfVertex(); i++) {
    			if(!isVisited[i]) {
    				dfs(isVisited, i);
    			}
    		}
    	}
    	
    	//广度优先遍历
    	private void bfs(boolean[] isVisited, int i) {
    		int u ; 
    		int w ; 
    		LinkedList queue = new LinkedList();
    		System.out.print(getValueByIndex(i) + "=>");
    		isVisited[i] = true;
    		queue.addLast(i);
    		
    		while( !queue.isEmpty()) {
    			u = (Integer)queue.removeFirst();
    			w = getFirstNeighbor(u);
    			while(w != -1) {
    				if(!isVisited[w]) {
    					System.out.print(getValueByIndex(w) + "=>");
    					isVisited[w] = true;
    					queue.addLast(w);
    				}
    				w = getNextNeighbor(u, w); 
    			}
    		}
    		
    	} 
    	
    	public void bfs() {
    		isVisited = new boolean[vertexList.size()];
    		for(int i = 0; i < getNumOfVertex(); i++) {
    			if(!isVisited[i]) {
    				bfs(isVisited, i);
    			}
    		}
    	}
    	
    	public int getNumOfVertex() {
    		return vertexList.size();
    	}
                           
    	//遍历
    	public void showGraph() {
    		for(int[] link : edges) {
    			System.err.println(Arrays.toString(link));
    		}
    	}
                           
    	public int getNumOfEdges() {
    		return numOfEdges;
    	}
    
    	public String getValueByIndex(int i) {
    		return vertexList.get(i);
    	}
                           
    	public int getWeight(int v1, int v2) {
    		return edges[v1][v2];
    	}
                           
    	//添加邻接矩阵
    	public void insertVertex(String vertex) {
    		vertexList.add(vertex);
    	}
    	
      //插入权值
    	public void insertEdge(int v1, int v2, int weight) {
    		edges[v1][v2] = weight;
    		edges[v2][v1] = weight;
    		numOfEdges++;
    	}
    }
    
    

    深度优先遍历,从初始访问结点出发,初始访问结点可能有多个邻接结点,深度优先遍历的策略就是首先访问第一个邻接结点,然后再以这个被访问的邻接结点作为初始结点,访问它的第一个邻接结点, 可以这样理解:每次都在访问完当前结点后首先访问当前结点的第一个邻接结点

    算法
    • 访问初始结点v,并标记结点v为已访问。
    • 查找结点v的第一个邻接结点w。
    • 若w存在,则继续执行4,如果w不存在,则回到第1步,将从v的下一个结点继续。
    • 若w未被访问,对w进行深度优先遍历递归(即把w当做另一个v,然后进行步骤123)。
    • 查找结点v的w邻接结点的下一个邻接结点,转到步骤3
    代码
    //深度优先遍历
    private void dfs(boolean[] isVisited, int i) {
      System.out.print(getValueByIndex(i) + "->");
      isVisited[i] = true;
      int w = getFirstNeighbor(i);
      while(w != -1) {
        if(!isVisited[w]) {
          dfs(isVisited, w);
        }
        w = getNextNeighbor(i, w);
      }
    
    }
    
    public void dfs() {
      isVisited = new boolean[vertexList.size()];
      for(int i = 0; i < getNumOfVertex(); i++) {
        if(!isVisited[i]) {
          dfs(isVisited, i);
        }
      }
    }
    

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

    算法
    • 访问初始结点v并标记结点v为已访问。
    • 结点v入队列
    • 当队列非空时,继续执行,否则算法结束。
    • 出队列,取得队头结点u。
    • 查找结点u的第一个邻接结点w。
    • 若结点u的邻接结点w不存在,则转到步骤3;否则循环执行以下三个步骤:
      • 若结点w尚未被访问,则访问结点w并标记为已访问。
      • 结点w入队列
      • 查找结点u的继w邻接结点后的下一个邻接结点w,转到步骤6
    代码
    //广度优先遍历
    private void bfs(boolean[] isVisited, int i) {
      int u ; 
      int w ; 
      LinkedList queue = new LinkedList();
      System.out.print(getValueByIndex(i) + "=>");
      isVisited[i] = true;
      queue.addLast(i);
    
      while( !queue.isEmpty()) {
        u = (Integer)queue.removeFirst();
        w = getFirstNeighbor(u);
        while(w != -1) {
          if(!isVisited[w]) {
            System.out.print(getValueByIndex(w) + "=>");
            isVisited[w] = true;
            queue.addLast(w);
          }
          w = getNextNeighbor(u, w); 
        }
      }
    
    } 
    
    public void bfs() {
      isVisited = new boolean[vertexList.size()];
      for(int i = 0; i < getNumOfVertex(); i++) {
        if(!isVisited[i]) {
          bfs(isVisited, i);
        }
      }
    }
    

    感谢

    尚硅谷

    以及勤劳的自己,个人博客GitHub

    微信公众号

  • 相关阅读:
    JSTL 配置
    HTML5 移动端web
    PHP 和 AJAX MySQL
    js php 互调
    google F12
    Codechef TRIPS Children Trips (分块、倍增)
    BZOJ 1859 Luogu P2589 [ZJOI2006]碗的叠放 (计算几何)
    AtCoder AGC002E Candy Piles (博弈论)
    BZOJ 2716 [Violet 3]天使玩偶 (CDQ分治、树状数组)
    AtCoder AGC001F Wide Swap (线段树、拓扑排序)
  • 原文地址:https://www.cnblogs.com/guizimo/p/13613238.html
Copyright © 2011-2022 走看看