JAVA數據結構----圖的存儲結構之鄰接矩陣

數據結構系列是我學習做的筆記,會持續更新,源碼分享在github:數據結構,當然你也可以從下面的代碼片中獲取
注:github代碼更新會有延遲,關注不迷路😄

本篇博文簡單介紹鄰接矩陣與其存儲圖的特點,並用java實現

1. 鄰接矩陣(Adjacency Matrix)

教科書上定義:圖的鄰接矩陣是用來表示頂點之間相鄰關係的矩陣。

鄰接矩陣是一個二維數組arcs[ ][ ],數組的行數和列數都與圖的頂點數相同

在沒有權值的時候,若圖中的第a個頂點和第b個頂點之間有連接,則arcs[ a ][ b ] = 1,無連接則爲定義爲0。由此定義可以簡單得出,無向圖的鄰接矩陣沿arc[ i ][ i ]軸對稱,一般採用壓縮存儲。

當圖的邊有權值爲x,若圖中的第a個頂點和第b個頂點之間有連接,則arcs[ a ][ b ] = x,無連接則爲定義爲正無窮,即Integer.MAX_VALUE。

有以下特點:

  • 1.用鄰接矩陣存儲圖,所需要的存儲空間只和定點數有關
    
  • 2.容易判斷任意倆頂點是否有邊,容易求出各個頂點上的度
    
  • 3.對於無向圖,鄰接矩陣第i行或i列非0元素個數正好是第i個頂點vi的度
    
  • 4.對於有向圖,第i行非0元素個數爲i個頂點的出度,i列爲入度
    

2. 圖的實現

2.1 圖的類型: GraphKind.java

圖的類型主要有四種,無向圖,有向圖,無向網(帶權圖),有向網,我們使用枚舉表示:

package code.Graph;

/*
* 羅列圖的四種類型
* */
public enum GraphKind {
    UDG,        //無向圖----(UnDirected Graph)

    DG,         //有向圖----(Directed Graph)

    UDN,        //無向網----(UnDirected Network)

    DN;         //有向網----(Directed Network)

}
2.2 圖的定義(接口): IGraph.java
package code.Graph;
/*
 * 圖的存儲結構除了存儲圖中各個頂點的信息外,還要存儲與頂點相關聯的邊的信息,
 * 圖的常見存儲結構有鄰接矩陣,鄰接表,鄰接多重表,十字鏈表
 *
 * 圖的接口
 *
 * */
public interface IGraph {

    /**創建一個圖*/
    public void createGraph();

    /**返回圖中的頂點數*/
    public int getVexNum();

    /**返回圖中的邊數*/
    public int getArcNum();

    /**
    * 給定點的位置v,返回其對應的頂點值,其中, 0 <=  v  < vexNum
     * @param v
    * */
    public Object getVex(int v) throws Exception;

    /**
    * 給定頂點的值vex,返回其在圖中的位置,如果圖中不包含此定點,返回-1
     * @param vex
    */
    public int locateVex(Object vex);

    /**
    * 返回v的第一個鄰接點,若V沒有鄰接點,則返回-1,其中, 0 <=  v  < vexNum
     * @param v
    */
    public int firstAdjVex(int v) throws Exception;

    /**
    * 返回v相對於w的下一個鄰接點,若w是v的最後一個鄰接點,則返回-1,其中, 0 <= v,  w  < vexNum
     * @param v
     * @param w
    */
    public int nextAdjVex(int v,int w) throws Exception;
}

2.3 鄰接矩陣存儲圖實現類: MGraph.java
package code.Graph;

import java.util.Scanner;

/**
 * @author 大青兒學習筆記
 *
 * 使用鄰接矩陣表示圖
 *
 * 注意點:
 *      1.無向圖的鄰接矩陣是對稱陣,一般採用壓縮存儲
 *
 *      2.用鄰接矩陣存儲圖,所需要的存儲空間只和定點數有關
 *
 *      3.優點:容易判斷任意倆頂點是否有邊,容易求出各個頂點上的度
 *
 *      4.對於無向圖,鄰接矩陣第i行或i列非0元素個數正好是第i個頂點vi的度
 *        對於有向圖,第i行非0元素個數爲i個頂點的出度,i列爲入度
 *
 *      0.圖的鄰接矩陣----(Adjacency Matrix)是用來表示頂點之間相鄰關係的矩陣
 *        圖的鄰接矩陣是一個n階矩陣,n爲頂點個數
 * */
public class MGraph implements IGraph{

    public final static int INFINITY = Integer.MAX_VALUE;//這裏表示網絡不連通,他們之間的權值也是無窮大

    private GraphKind kind;     //圖的種類標誌

    private int vexNum,arcNum;  //圖的當前頂點數和邊數

    private Object [] vexs;     //頂點數組

    private int [][]arcs;       //鄰接矩陣

    public MGraph(){
        this(null,0,0,null,null);
    }

    public MGraph(GraphKind kind, int vexNum, int arcNum, Object[] vexs, int[][] arcs) {
        this.kind = kind;
        this.vexNum = vexNum;
        this.arcNum = arcNum;
        this.vexs = vexs;
        this.arcs = arcs;
    }

    /**
     * 創建一個圖
     */
    @Override
    public void createGraph() {
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入圖的類型:");
        GraphKind kind = GraphKind.valueOf(sc.next());
        switch (kind){
            case UDG:
                createUDG();
                return;
            case DG:
                createDG();
                return;
            case UDN:
                createUDN();
                return;
            case DN:
                createDN();
                return;
        }
    }

    //創建 圖,網 的工具方法
    private void createNetworkOrGraphUnit(){
        Scanner sc = new Scanner(System.in);
        System.out.println("請分別輸入圖的頂點數,圖的邊數");
        vexNum = sc.nextInt();//圖的頂點數
        arcNum = sc.nextInt();//圖的邊數

        vexs = new Object[vexNum];//存儲頂點的數組

        System.out.println("請分別輸入圖的各個頂點:");
        for (int v = 0;v < vexNum;v++){//構造頂點向量
            vexs[v] = sc.next();
        }

        arcs = new int[vexNum][vexNum];//創建鄰接矩陣
        //初始化鄰接矩陣
        for (int v = 0;v < vexNum;v++){
            for (int u = 0;u < vexNum;u++){
                arcs[v][u] = INFINITY;//設初始的全部的權值爲最大
            }
        }
    }

    /*
    * 創建無向圖
    *   書上的方法
    *
    *   我本人更傾向於傳參式的方法
    * */
    private void createUDG(){
        Scanner sc = new Scanner(System.in);
        createNetworkOrGraphUnit();
        System.out.println("請輸入各個邊的兩個頂點及其權值:");
        for(int k = 0; k <arcNum;k++){//循環 圖的邊數 次
            int v = locateVex(sc.next());
            int u = locateVex(sc.next());
            arcs[v][u] = arcs[u][v] = 1;
        }

    }

    /*
     * 創建有向圖
     *   書上的方法
     *
     *   我本人更傾向於傳參式的方法
     * */
    private void createDG(){
        Scanner sc = new Scanner(System.in);
        createNetworkOrGraphUnit();
        System.out.println("請輸入各個邊的兩個頂點及其權值:");
        for(int k = 0; k <arcNum;k++){//循環 圖的邊數 次
            int v = locateVex(sc.next());
            int u = locateVex(sc.next());
            arcs[v][u]= 1;
        }
    }

    /*
    * 創建無向網
    *   書上的方法
    *
    *   我本人更傾向於傳參式的方法
    * */
    private void createUDN(){
        Scanner sc = new Scanner(System.in);
        createNetworkOrGraphUnit();
        System.out.println("請輸入各個邊的兩個頂點及其權值:");
        for(int k = 0; k <arcNum;k++){//循環 圖的邊數 次
            int v = locateVex(sc.next());
            int u = locateVex(sc.next());
            arcs[v][u] = arcs[u][v] = sc.nextInt();
        }

    }

    /*
     * 創建有向網
     *   書上的方法
     *
     *   我本人更傾向於傳參式的方法
     * */
    private void createDN(){
        Scanner sc = new Scanner(System.in);
        createNetworkOrGraphUnit();
        System.out.println("請輸入各個邊的兩個頂點及其權值:");
        for(int k = 0; k <arcNum;k++){//循環 圖的邊數 次
            int v = locateVex(sc.next());
            int u = locateVex(sc.next());
            arcs[v][u]= sc.nextInt();
        }
    }

    /**
     * 返回圖中的頂點數
     */
    @Override
    public int getVexNum() {
        return vexNum;
    }

    /**
     * 返回圖中的邊數
     */
    @Override
    public int getArcNum() {
        return arcNum;
    }

    /**
     * 給定點的位置v,返回其對應的頂點值,其中, 0 <=  v  < vexNum
     *
     * @param v
     */
    @Override
    public Object getVex(int v) throws Exception {
        if (v < 0 && v >= vexNum){
            throw new Exception("第"+v+"個頂點不存在");
        }
        return vexs[v];
    }

    /**
     * 給定頂點的值vex,返回其在圖中的位置,如果圖中不包含此定點,返回-1
     *
     * @param vex
     */
    @Override
    public int locateVex(Object vex) {
        for (int v = 0;v < vexNum;v++){
            if (vexs[v].equals(vex)){
                return v;
            }
        }

        return -1;
    }

    /**
     * 返回v的第一個鄰接點,若V沒有鄰接點,則返回-1,其中, 0 <=  v  < vexNum
     *
     * @param v
     */
    @Override
    public int firstAdjVex(int v) throws Exception {
        if (v < 0 && v >= vexNum){
            throw new Exception("第" + v + "個頂點不存在!");
        }
        for (int j = 0;j<vexNum;j++){
            if (arcs[v][j] != 0 && arcs[v][j] < INFINITY){
                return j;
            }
        }
        return -1;
    }

    /**
     * 返回v相對於w的下一個鄰接點,若w是v的最後一個鄰接點,則返回-1,其中, 0 <= v,  w  < vexNum
     *
     * @param v
     * @param w
     */
    @Override
    public int nextAdjVex(int v, int w) throws Exception {
        if (v < 0 && v >= vexNum){
            throw new Exception("第" + v + "個頂點不存在!");
        }
        if (w >= vexNum){
            throw new Exception("相對頂點不存在!");
        }

        for (int j = w + 1;j < vexNum;j++){
            if (arcs[v][j] != 0 && arcs[v][j] <INFINITY){
                return  j;
            }
        }

        return -1;
    }

    public GraphKind getKind() {
        return kind;
    }

    public Object[] getVexs() {
        return vexs;
    }

    public int[][] getArcs() {
        return arcs;
    }
}

有關圖的鄰接表java實現見此鏈接

發佈了27 篇原創文章 · 獲贊 49 · 訪問量 2258
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章