Java数据结构算法(四)图

本文旨作于收集整理使用!!

导航

  • Java数据结构算法(一)链表
  • Java数据结构算法(二)栈和队列
  • Java数据结构算法(三)树
  • Java数据结构算法(五)排序
  • ......

一、图的简介

图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。在图中的数据元素,我们称之为顶点(Vertex),顶点集合有穷非空。在图中,任意两个顶点之间都可能有关系,顶点之间的逻辑关系用边来表示,边集可以是空的。
图主要运用在路径规划以及模型建立中。

二、图的分类

1、 无向图

若顶点v1到v2之间的边没有方向,则称这条边为无向边。如果图中任意两个顶点之间的边都是无向边,则称该图为无向图。
在无向图中,若任意两个顶点之间都存在边,则称该图为无向完全图

无向图.png

2、 有向图

有向边:若顶点v1到v2的边有方向,则称这条边为有向边或为弧。
若图中任意两个顶点之间的连线都是有向边,则称该图为有向图。
在有向图中,若任意两个顶点之间都存互为相反的两条弧,则称该图为有向完全图

有向图

3、其他

权:有些图的边或弧具有与他相关的数字,这种与图相关的边或弧叫做权。
连通图:在无向图中任意两个顶点之间都是连通的。
度:无向图顶点的边数叫做度;有向图的边数叫做出度和入度。

三、图的存储结构

图的存储结构较为复杂,无法用简单的顺序存储结构存储,因此使用邻接矩阵来存储图。
邻接矩阵的存储方式是用一维数组存储顶点信息,用二维数组存储图中边或弧的信息。

1、无向图

设图有n个顶点,则邻接矩阵就是一个n×n的方阵,定义为:

若两个顶点之间有连线则值为1,若无连线则为0。如下图所示

2、有向图

设图有n个顶点,则邻接矩阵就是一个n×n的方阵,定义为:

若两个顶点之间从一个顶点到另一个顶点之间有对应的箭头则为1,无则为0。如下图所示,v1到v0有弧线则为1,而v0到v1无弧则为0.

3、带权的图

设图有n个顶点,则邻接矩阵就是一个n×n的方阵,定义为:

我们将对应连线之间的权作为连线的依据,两定点之间无弧线咋舌为无穷大,有弧线则设为对应的权值。

4、图的简单实现(JAVA)

/**
 * Author: Active_Loser
 * Date: 2018/8/1 22:24
 * Content:
 */
public class Graph {
    private static final int MAX_WEIGHT = 1000;
    private int vertexSize;
    private int[] vertexs;
    private int[][] matrix;
    private boolean[] isVisted;

    public Graph(int vertexSize) {
        this.vertexSize = vertexSize;
        matrix = new int[vertexSize][vertexSize];
        vertexs = new int[vertexSize];
        for (int i = 0; i < vertexSize; i++) {
            vertexs[i] = i;
        }
        isVisted = new boolean[vertexSize];
    }

    /**
     * 获取某个顶点的出度
     *
     * @param index 顶点下标
     * @return 返回该顶点的出度
     */
    public int getOutDeGree(int index) {
        int deGree = 0;
        for (int i = 0; i < matrix[index].length; i++) {
            int weight = matrix[index][i];
            if (weight != 0 && weight != MAX_WEIGHT) {
                deGree++;
            }
        }
        return deGree;
    }

    /**
     * 获取某个顶点的入度
     *
     * @param index 顶点下标
     * @return 返回该顶点的出度
     */
    public int getIntDeGree(int index) {
        int deGree = 0;
        for (int i = 0; i < vertexSize; i++) {
            int weight = matrix[i][index];
            if (weight != 0 && weight != MAX_WEIGHT) {
                deGree++;
            }
        }
        return deGree;
    }

    /**
     * 获取权值
     *
     * @param v1
     * @param v2
     * @return
     */
    public int getWeight(int v1, int v2) {
        return matrix[v1][v2] == 0 ? 0 : (matrix[v1][v2] == MAX_WEIGHT ? -1 : matrix[v1][v2]);
    }

    public int[][] getMatrix() {
        return matrix;
    }
}

图的构造,实现带权的图

private static final int MAX_WEIGHT = 1000;

    public static void main(String[] args) {
        Graph graph = new Graph(4);
        int[] a0 = {0, MAX_WEIGHT, MAX_WEIGHT, 1};
        int[] a1 = {30, 0, MAX_WEIGHT, MAX_WEIGHT};
        int[] a2 = {4, 15, 0, 5};
        int[] a3 = {MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 0};
        int[][] matrix = graph.getMatrix();
        matrix[0]=a0;
        matrix[1]=a1;
        matrix[2]=a2;
        matrix[3]=a3;
        //graph.方法
    }

四、图的遍历

1、图的深度优先遍历

深度优先遍历(Depth_First_Search(DFS))也被称为深度优先搜索,它是从图中的某个v点出发,访问此顶点,然后从v的未被访问的点邻接点出发深度优先遍历,直到图中所有和v点有路径相通的点都被访问到。
图的深度优先遍历类似于树的前序遍历,如下图,可以将树转化为图。


深度优先遍历

深度优先遍历主要代码,完整代码移至最后。

/**
     * 深度优先遍历,对外界提供访问
     */
    public void dfs(int index) {
        if (index<0||index>vertexSize-1){
            return;
        }
        //重新初始化
        isVisted = new boolean[vertexSize];
        //优先访问开始的点
        System.out.println("访问到了"+index+"顶点");
        depth_first_search(index);
        //通过遍历查看那些点没有被访问(主要针对于有向图)
        for (int i = 0; i < vertexSize; i++) {
            if (!isVisted[i]) {
                System.out.println("访问到了"+i+"顶点");
                depth_first_search(i);
            }
        }
        //重新初始化
        isVisted = new boolean[vertexSize];
    }

    /**
     * 提供访问的方法
     * @param index
     */
    private void depth_first_search(int index) {
        isVisted[index] = true;
        int w = getFirstNeighbor(index);
        while (w!=-1){
            if (!isVisted[w]){
                depth_first_search(w);
                System.out.println("访问到了"+w+"顶点");
            }
            w=getNextNeighbor(index,w);
        }
    }

    //获取某个顶点的第一个邻接点
    private int getFirstNeighbor(int v1) {
        for (int i = 0; i < vertexSize; i++) {
            if (matrix[v1][i] > 0 && matrix[v1][i] < MAX_WEIGHT) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 根据前一个邻接点的下标获取一个邻接点
     *
     * @param v1    表示查找的顶点
     * @param index 表示该顶点相对于哪个邻接点获取下一个邻接点
     * @return
     */
    private int getNextNeighbor(int v1, int index) {
        for (int i = index+1; i < vertexSize; i++) {
            if (matrix[index][i] > 0 && matrix[index][i] < MAX_WEIGHT) {
                return i;
            }
        }
        return -1;
    }

2、图的广度优先遍历

图的广度优先遍历,类似于树种的层次遍历,如下图将图转化为可以广层次遍历的树。



广度优先遍历主要代码,完整代码移至最后。

 /**
     * 实现广度优先遍历
     *
     * @param index
     */
    public void bfs(int index) {
        //重新初始化
        isVisted = new boolean[vertexSize];
        //优先访问开始的点
        System.out.println("访问到了"+index+"顶点");
        depth_first_search(index);
        //通过遍历查看那些点没有被访问(主要针对于有向图)
        for (int i = 0; i < vertexSize; i++) {
            if (!isVisted[i]) {
                System.out.println("访问到了" + i + "顶点");
                broadFirstSearch(i);
            }
        }
        //重新初始化
        isVisted = new boolean[vertexSize];

    }

    /**
     * 广度优先遍历算法
     *
     * @param index
     */
    private void broadFirstSearch(int index) {
        int u, w;
        //使用队列实现
        LinkedList queue = new LinkedList<>();
        isVisted[index] = true;
        queue.add(index);
        while (!queue.isEmpty()){
            u= queue.removeFirst();
            w=getFirstNeighbor(u);
            while (w!=-1){
                if (!isVisted[w]){
                    System.out.println("访问到了" + w + "顶点");
                    isVisted[w]=true;
                    queue.add(w);
                }
                w=getNextNeighbor(u,w);
            }
        }
    }
 //获取某个顶点的第一个邻接点
    private int getFirstNeighbor(int v1) {
        for (int i = 0; i < vertexSize; i++) {
            if (matrix[v1][i] > 0 && matrix[v1][i] < MAX_WEIGHT) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 根据前一个邻接点的下标获取一个邻接点
     *
     * @param v1    表示查找的顶点
     * @param index 表示该顶点相对于哪个邻接点获取下一个邻接点
     * @return
     */
    private int getNextNeighbor(int v1, int index) {
        for (int i = index + 1; i < vertexSize; i++) {
            if (matrix[index][i] > 0 && matrix[index][i] < MAX_WEIGHT) {
                return i;
            }
        }
        return -1;
    }

完整代码

import java.util.LinkedList;

/**
 * Author: Active_Loser
 * Date: 2018/8/1 22:24
 * Content:
 */
public class Graph {
    private static final int MAX_WEIGHT = 1000;
    private int vertexSize;
    private int[] vertexs;
    private int[][] matrix;
    private boolean[] isVisted;


    public Graph(int vertexSize) {
        this.vertexSize = vertexSize;
        matrix = new int[vertexSize][vertexSize];
        vertexs = new int[vertexSize];
        for (int i = 0; i < vertexSize; i++) {
            vertexs[i] = i;
        }
        isVisted = new boolean[vertexSize];
    }

    /**
     * 深度优先遍历,对外界提供访问
     */
    public void dfs(int index) {
        if (index < 0 || index > vertexSize - 1) {
            return;
        }
        //重新初始化
        isVisted = new boolean[vertexSize];
        //优先访问开始的点
        System.out.println("访问到了" + index + "顶点");
        depth_first_search(index);
        //通过遍历查看那些点没有被访问(主要针对于有向图)
        for (int i = 0; i < vertexSize; i++) {
            if (!isVisted[i]) {
                System.out.println("访问到了" + i + "顶点");
                depth_first_search(i);
            }
        }
        //重新初始化
        isVisted = new boolean[vertexSize];
    }

    /**
     * 提供访问的方法
     *
     * @param index
     */
    private void depth_first_search(int index) {
        isVisted[index] = true;
        int w = getFirstNeighbor(index);
        while (w != -1) {
            if (!isVisted[w]) {
                depth_first_search(w);
                System.out.println("访问到了" + w + "顶点");
            }
            w = getNextNeighbor(index, w);
        }
    }

    //获取某个顶点的第一个邻接点
    private int getFirstNeighbor(int v1) {
        for (int i = 0; i < vertexSize; i++) {
            if (matrix[v1][i] > 0 && matrix[v1][i] < MAX_WEIGHT) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 根据前一个邻接点的下标获取一个邻接点
     *
     * @param v1    表示查找的顶点
     * @param index 表示该顶点相对于哪个邻接点获取下一个邻接点
     * @return
     */
    private int getNextNeighbor(int v1, int index) {
        for (int i = index + 1; i < vertexSize; i++) {
            if (matrix[index][i] > 0 && matrix[index][i] < MAX_WEIGHT) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 实现广度优先遍历
     *
     * @param index
     */
    public void bfs(int index) {
        //重新初始化
        isVisted = new boolean[vertexSize];
        //优先访问开始的点
        System.out.println("访问到了"+index+"顶点");
        depth_first_search(index);
        //通过遍历查看那些点没有被访问(主要针对于有向图)
        for (int i = 0; i < vertexSize; i++) {
            if (!isVisted[i]) {
                System.out.println("访问到了" + i + "顶点");
                broadFirstSearch(i);
            }
        }
        //重新初始化
        isVisted = new boolean[vertexSize];

    }

    /**
     * 广度优先遍历算法
     *
     * @param index
     */
    private void broadFirstSearch(int index) {
        int u, w;
        //使用队列实现
        LinkedList queue = new LinkedList<>();
        isVisted[index] = true;
        queue.add(index);
        while (!queue.isEmpty()){
            u= queue.removeFirst();
            w=getFirstNeighbor(u);
            while (w!=-1){
                if (!isVisted[w]){
                    System.out.println("访问到了" + w + "顶点");
                    isVisted[w]=true;
                    queue.add(w);
                }
                w=getNextNeighbor(u,w);
            }
        }
    }

    /**
     * 获取某个顶点的出度
     *
     * @param index 顶点下标
     * @return 返回该顶点的出度
     */
    public int getOutDeGree(int index) {
        int deGree = 0;
        for (int i = 0; i < matrix[index].length; i++) {
            int weight = matrix[index][i];
            if (weight != 0 && weight != MAX_WEIGHT) {
                deGree++;
            }
        }
        return deGree;
    }

    /**
     * 获取某个顶点的入度
     *
     * @param index 顶点下标
     * @return 返回该顶点的出度
     */
    public int getIntDeGree(int index) {
        int deGree = 0;
        for (int i = 0; i < vertexSize; i++) {
            int weight = matrix[i][index];
            if (weight != 0 && weight != MAX_WEIGHT) {
                deGree++;
            }
        }
        return deGree;
    }

    /**
     * 获取权值
     *
     * @param v1
     * @param v2
     * @return
     */
    public int getWeight(int v1, int v2) {
        return matrix[v1][v2] == 0 ? 0 : (matrix[v1][v2] == MAX_WEIGHT ? -1 : matrix[v1][v2]);
    }

    public int[][] getMatrix() {
        return matrix;
    }
}

你可能感兴趣的:(Java数据结构算法(四)图)