数据结构与算法 21 图结构 深度优先遍历 广度优先遍历

概念

  1. 顶点 vertex
  2. 边 edge
  3. 路径
  4. 无向图:顶点之间的连接没有方向
  5. 有向图:顶点之间的连接有方向
  6. 带权图:边带有权值,也叫网

图的表示方法

二维数组表示(邻接矩阵);链表表示(邻接表)

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

邻接表

  1. 邻接矩阵需要为每个顶点都分配n个边的空间,其实有很多边都是不存在的,会造成空间的一定损失
  2. 邻接表的实现只关心存在的边,不关系不存在的边,因此没有空间浪费,邻接表由数组+链表组成

代码实现图结构

  1. 存储顶点 String ArrayList
  2. 保存矩阵:二维数组 int/[]/[] edges
package graph;

import java.util.ArrayList;
import java.util.Arrays;

public class GraphDemo01 {
    private ArrayList<String> vertexList; // store vertex
    private int[][] edges; // preliminary matrix corresponding to graph
    private int numOfEdges; // # of edges

    public static void main(String[] args) {
        int n = 5;
        String VertexValue[] = {"A","B","C","D","E"};
        // create graph object
        GraphDemo01 graph = new GraphDemo01(n);
        // add vertex
        for(String value:VertexValue){
            graph.insertVertex(value);
        }
        // add edges
        graph.insertEdge(0,1,1);
        graph.insertEdge(0,2,1);
        graph.insertEdge(1,2,1);
        graph.insertEdge(1,3,1);
        graph.insertEdge(1,4,1);
        // show
        graph.showGrapgh();

    }
    // constructor
    public GraphDemo01(int n){
        // initialize vertex and vertexList
        edges = new int[n][n];
        vertexList = new ArrayList<String>(n);
        numOfEdges = 0;
    }

    // commonly used methods in graph
    // return nums of vertex
    public int getNumOfVertex(){
        return vertexList.size();
    }
    // get nums of edges
    public int getNumOfEdges(){
        return numOfEdges;
    }
    // return info of vertex i, eg: 0-"A" 1-"B" 2-"C"
    public  String getValueByIndex(int i){
        return vertexList.get(i);
    }
    // return weight between v1 and v2
    public int getWeight(int v1,int v2){
        return edges[v1][v2];
    }
    // show the matrix corresponding the graph
    public void showGrapgh(){
        for(int[] link:edges){
            System.out.println(Arrays.toString(link));
        }
    }

    // insert vertex
    public void insertVertex(String vertex){
        vertexList.add(vertex);
    }

    // add edges
    /**
     * add edges
     * @param v1 index of the first vertex
     * @param v2 index of the second vertex
     * @param weight weight between v1 and v2
     */
    public void insertEdge(int v1, int v2, int weight){
        edges[v1][v2] = weight;
        edges[v2][v1] = weight;
        numOfEdges++;
    }

}

图遍历

图遍历,即对节点的访问

策略:深度优先遍历;广度优先遍历

深度优先遍历

Depth First Search

  1. 从初始访问节点出发,初始访问节点可能有多个邻接节点,深度优先遍历的策略就是首先访问第一个邻接节点,然后再以这个被访问的邻接节点作为初始节点,访问它的第一个邻接节点。可以理解为:每次都在访问完当前节点后首先访问当前节点的第一个邻接节点
  2. 优先往纵向挖掘深入,而不是对一个节点所有邻接节点进行横向访问
  3. 深度优先搜索是一个递归的过程

算法步骤:

  1. 访问初始节点 v,并标记节点 v 为已访问
  2. 查找节点 v 的第一个邻接节点 w
  3. 若 w 存在,则继续执行 4,若 w不存在,则回到第1步,将从 v 的下一个节点继续
  4. 若 w 未被访问,对 w 进行深度优先遍历递归(即把 w 当作另一个 v,然后进行步骤 1,2,3)
  5. 查找节点 v 的 w 邻接节点的下一个邻接节点,转到步骤 3

代码

// constructor
    public GraphDemo01(int n){
        // initialize vertex and vertexList
        edges = new int[n][n];
        vertexList = new ArrayList<String>(n);
        numOfEdges = 0;
        isVisited = new boolean[5];
    }


    /**
     * get the index of the first preliminary node
     * @param index
     * @return if exists, return index, or return -1
     */
    public int getFirstNeighbor(int index){
        for(int j = 0; j<vertexList.size();j++){
            if(edges[index][j]>0){
                return j;
            }
        }
        return -1;
    }

    // get next neighbor node according to index of previous neighbor node
    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;
    }

    // dfs
    // At first: i is 0
    private void dfs(boolean[] isVisited,int i){
        // visit (output) this node
        System.out.println(getValueByIndex(i)+" -> ");
        // set status of this node to visited
        isVisited[i] = true;
        // the first neighbor of i
        int w = getFirstNeighbor(i);
        while(w!=-1){
            if(!isVisited[w]){
                dfs(isVisited,w);
            }
            // if w has been visited
            w = getNextNeighbor(i,w);
        }
    }

    // override dfs, traverse all node and do dfs
    public void dfs(){
        for (int i = 0; i < getNumOfVertex(); i++) {
            if(!isVisited[i]){
                dfs(isVisited,i);
            }
        }
    }
// main function
        // test dfs
        System.out.println("dfs");
        graph.dfs();

广度优先遍历

Broad First Search

类似于一个分层搜索的过程,需要使用一个队列以保存访问过的节点的顺序,以按这个顺序来访问这些节点的邻接节点


算法步骤:

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

代码

 // bfs for one node (for loop for all nodes)
    private void bfs(boolean[] isVisited,int i){
        int u; // index of queue head
        int w; // index of preliminary node
        // queue: record order of node access
        LinkedList queue = new LinkedList();
        // visit this node, output it
        System.out.println(getValueByIndex(i)+" -> ");
        // mark as "visited"
        isVisited[i] = true;
        // add this node into queue(first in first out)
        queue.addLast(i);
        while(!queue.isEmpty()){
            // pick up the head of queue
            u = (Integer) queue.removeFirst();
            // get the index of the first preliminary node
            w = getFirstNeighbor(u);
            while(w!=-1){ // find it
                // whether it is visited
                if(!isVisited[w]){
                    System.out.println(getValueByIndex(w)+" -> ");
                    // mark it as visited
                    isVisited[w] = true;
                    // in queue
                    queue.addLast(w);
                }
                // visited already
                // take u as the previous node,find next preliminary node of w
                w = getNextNeighbor(u,w);

            }
        }
    }

    // traverse all node, do bfs
    public void bfs(){
        for (int i = 0; i < getNumOfVertex(); i++) {
            if(!isVisited[i]){
                bfs(isVisited,i);
            }
        }
    }
// main methods
        // test bfs
        System.out.println("bfs");
        graph.bfs();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值