數據結構與算法筆記:圖的基礎與JAVA實現

圖是由頂點集(VertexSet)和邊集(EdgeSet)組成,針對圖G,頂點集和邊集分別記爲V(G)和E(G)。java

依據圖的邊集是否爲有向,可把圖分爲有向圖無向圖node

根據圖是否有權重,能夠分爲有權圖無權圖算法

public interface Graph {
    boolean insertEdge(int v1,int v2,int weight);
    boolean deleteEdge(int v1,int v2);
    int getDegree(int v);
    int getInDegree(int v);
    int getOutDegree(int v);
    String depthFirstSearch(int v);
    String breathFirstSearch(int v);
    GraphType getGraphType();
    int getFirstNeighbor(int v); // none return -1
    int getNextNeighbor(int v,int v2); // none return -1
    int getSize();
    int getWeight(int v1,int v2);
    int getEdgeSize();
}

圖的基本知識

圖的概念

圖是由頂點集(VertexSet)和邊集(EdgeSet)組成,針對圖G,頂點集和邊集分別記爲V(G)和E(G)。數組

依據圖的邊集是否爲有向,可把圖分爲有向圖無向圖緩存

根據圖是否有權重,能夠分爲有權圖無權圖數據結構

圖的基本術語:app

  1. 鄰接點:在一個無向圖中,若存在一條邊(Vi,Vj),則稱Vi,Vj爲此邊的兩個端點,並稱它們互爲鄰接點ide

  2. 出/入邊:在一個有向圖張,若存在一條邊<Vi,Vj>,則稱此邊爲頂點Vi的出邊,頂點Vj的一條入邊;函數

  3. 度/入度/出度:無向圖中的度定義爲以該頂點爲一個端點的邊的數目,記爲D(V)。有向圖的入度定義爲多少邊指向該頂點,出度是該頂點出邊的個數;this

注意:這裏不考慮自環和多重邊

圖的表示方式

圖的表示方式有兩種:

  • 二維數組表示(鄰接矩陣)
  • 鏈表表示(鄰接表)

(1)鄰接矩陣表示(Adjacency Matrix)

在無向圖中,鄰接矩陣是對稱的;

在無權圖中,用0表示邊<i,j>是不鏈接的,用1表示邊<i,j>是鏈接的;

在有權圖中,用INF表示邊<i,j>是不鏈接的,用weight表示邊<i,j>是鏈接的;

圖的類型 示例
無向無權圖 graph_2
有向無權圖 graph_3
有向有權圖 graph_4

(2)鄰接表表示(Linked-adjacency Lists)

鄰接矩陣與鄰接表相比,它會形成空間的必定損失,它須要爲每一個頂點都分配n個邊的空間,其實有不少邊都是不存在邊,可是鄰接表的實現就不同,它只關心存在的邊,不關心不存在的邊。鄰接表由數組+鏈表組成對於上面的無向圖,鄰接表表示爲(因爲有向和無向的差異不是太大,因此只是畫出了無向的鄰接表表示):

鄰接表

注:若要表示有權圖,將鄰接表的節點數據結構中增長一個weight數據便可

圖的JAVA實現

本程序只實現了基本功能,即節點表示爲1,2,..,n,暫不支持泛型與刪節點

圖的類型

圖有四種類型

  • 有向有權圖
  • 無向有權圖
  • 有向無權圖
  • 無向無權圖
public enum GraphType {
    DirectionWeight,
    NoDirectionWeight,
    DirectionNoWeight,
    NoDirectionNoWeight;
}

圖的接口類

定義一個圖的接口類,以下:

public interface Graph {
    boolean insertEdge(int v1,int v2,int weight);
    boolean deleteEdge(int v1,int v2);
    int getDegree(int v);
    int getInDegree(int v);
    int getOutDegree(int v);
    String depthFirstSearch(int v);
    String breathFirstSearch(int v);
    GraphType getGraphType();
    int getFirstNeighbor(int v); // none return -1
    int getNextNeighbor(int v,int v2); // none return -1
    int getSize();
    int getWeight(int v1,int v2);
    int getEdgeSize();
}

本程序只實現了基本功能,即節點表示爲1,2,..,n,暫不支持泛型與刪節點

具體實現

(1)LinkGraph類與MatrixGraph類

顧名思義,用鄰接表與鄰接矩陣實現圖。

實現了Graph接口,成員變量與構造函數以下:

public class LinkGraph implements Graph {
    
    private LinkedList<VertexNode>[] vexList;
    private int edgeSize; // 已有邊數
    private GraphType type;
    private int maxVertex; // 頂點最大個數
    private static final int INF = 999999; // 用於有權圖的無邊表示
    Iterator<VertexNode> temp; // 用於緩存getNeighbor方法的Iterator

    public LinkGraph(GraphType type, int size) {
        vexList = new LinkedList[size + 1];
        for (int i = 1; i < size + 1; i++) {
            vexList[i] = new LinkedList();
        }
        maxVertex = size;
        edgeSize = 0;
        this.type = type;
    }
    
    private class VertexNode { // 鄰接表節點的內部類
        int vertex;
        int weight;
        VertexNode(int vex, int weight) {
            vertex = vex;
            this.weight = weight;
        }
        VertexNode(int vex) {
            vertex = vex;
            this.weight = 1;
        }
    }
public class MatrixGraph implements Graph {

    private int[][] matrix;
    private int edgeSize; // 已有邊數
    private GraphType type;
    private int maxVertex; // 頂點最大個數
    private static final int INF = 999999; // 用於有權圖的無邊表示

    public MatrixGraph(GraphType type, int size) {
        matrix = new int[size + 1][size + 1];
        maxVertex = size;
        edgeSize = 0;
        this.type = type;
        switch (type) {
            case DirectionWeight:
            case NoDirectionWeight:
                for (int i = 0; i < size + 1; i++) {
                    for (int j = 0; j < size + 1; j++) {
                        matrix[i][j] = INF;
                    }
                }
                break;
            case DirectionNoWeight:
            case NoDirectionNoWeight:
                for (int i = 0; i < size + 1; i++) {
                    for (int j = 0; j < size + 1; j++) {
                        matrix[i][j] = 0;
                    }
                }
                break;
        }
    }

注意用鄰接矩陣實現時,由於圖的類型不一樣致使的表示不一樣,常須要先判斷,後進行操做。

(2)insertEdge方法與deleteEdge方法

boolean insertEdge(int v1,int v2,int weight);
    boolean deleteEdge(int v1,int v2);

這裏須要注意的地方是加邊和刪邊的時候要修改edgeSize變量,因此須要一些判斷語句

在無權圖中,不管weight爲多少咱們都把他看成1

鄰接表實現

@Override
    public boolean insertEdge(int v1, int v2, int weight) {
        if (v1 < 1 || v1 > maxVertex || v2 < 1 || v2 > maxVertex) {
            System.out.println("無效輸入,退出");
            return false;
        }
        boolean contain = false;
        switch (type) {
            case DirectionNoWeight:
                weight = 1;
            case DirectionWeight:
                for (VertexNode vex : vexList[v1]) {
                    if (vex.vertex == v2)
                        contain = true;
                }
                if (!contain)
                    edgeSize++;
                vexList[v1].add(new VertexNode(v2, weight));
                break;
            case NoDirectionNoWeight:
                weight = 1;
            case NoDirectionWeight:
                for (VertexNode vex : vexList[v1]) {
                    if (vex.vertex == v2)
                        contain = true;
                }
                if (!contain)
                    edgeSize++;
                vexList[v1].add(new VertexNode(v2, weight));
                vexList[v2].add(new VertexNode(v1, weight));
                break;
        }
        return true;
    }


    @Override
    public boolean deleteEdge(int v1, int v2) {
        if (v1 < 1 || v1 > maxVertex || v2 < 1 || v2 > maxVertex) {
            System.out.println("無效輸入,退出");
            return false;
        }
        Iterator<VertexNode> iterator;
        switch (type) {
            case DirectionNoWeight:
            case DirectionWeight:
                iterator = vexList[v1].listIterator(0);
                while (iterator.hasNext()) {
                    if (iterator.next().vertex == v2) {
                        iterator.remove();
                        edgeSize--;
                        break;
                    }
                }
                break;
            case NoDirectionWeight:
            case NoDirectionNoWeight:
                iterator = vexList[v1].listIterator(0);
                while (iterator.hasNext()) {
                    if (iterator.next().vertex == v2) {
                        iterator.remove();
                        edgeSize--;
                        iterator = vexList[v2].listIterator(0);
                        while (iterator.hasNext()) {
                            if (iterator.next().vertex == v1) {
                                iterator.remove();
                                edgeSize--;
                                break;
                            }
                            break;
                        }
                    }
                    break;
                }
        }
        return true;
    }

值得注意的是鄰接表實現中咱們加入的是內部類(VertexNode)做爲節點,所以在遍歷的時候用到了鏈表的Iterator

鄰接矩陣實現

@Override
    public boolean insertEdge(int v1, int v2, int weight) {
        if (v1 < 1 || v1 > maxVertex || v2 < 1 || v2 > maxVertex) {
            System.out.println("無效輸入,退出");
            return false;
        }
        switch (type) {
            case DirectionNoWeight:
                if (matrix[v1][v2] == 0)
                    edgeSize++;
                matrix[v1][v2] = 1;
                break;
            case NoDirectionNoWeight:
                if (matrix[v1][v2] == 0)
                    edgeSize++;
                matrix[v1][v2] = 1;
                matrix[v2][v1] = 1;
                break;
            case DirectionWeight:
                if (matrix[v1][v2] == INF)
                    edgeSize++;
                matrix[v1][v2] = weight;
                break;
            case NoDirectionWeight:
                if (matrix[v1][v2] == INF)
                    edgeSize++;
                matrix[v1][v2] = weight;
                matrix[v2][v1] = weight;
                break;
        }
        return true;
    }

    @Override
    public boolean deleteEdge(int v1, int v2) {
        if (v1 < 1 || v1 > maxVertex || v2 < 1 || v2 > maxVertex) {
            System.out.println("無效輸入,退出");
            return false;
        }
        switch (type) {
            case DirectionNoWeight:
                if (matrix[v1][v2] != 0)
                    edgeSize--;
                matrix[v1][v2] = 0;
                break;
            case NoDirectionNoWeight:
                if (matrix[v1][v2] != 0)
                    edgeSize--;
                matrix[v1][v2] = 0;
                matrix[v2][v1] = 0;
                break;
            case DirectionWeight:
                if (matrix[v1][v2] != INF)
                    edgeSize--;
                matrix[v1][v2] = INF;
                break;
            case NoDirectionWeight:
                if (matrix[v1][v2] != INF)
                    edgeSize--;
                matrix[v1][v2] = INF;
                matrix[v2][v1] = INF;
                break;
        }
        return true;
    }

(3)getDegree系列方法

int getDegree(int v);
    int getInDegree(int v);
    int getOutDegree(int v);

分別爲獲取v節點的度、入度、出度的方法。

第一個方法有一個統一的實現

public int getDegree(int v) {
        if (type == GraphType.NoDirectionWeight || type == GraphType.NoDirectionNoWeight)
            return getOutDegree(v); // 由於算起來比GetInDegree快
        else
            return getInDegree(v) + getOutDegree(v);
    }

鄰接表實現

鄰接表沒有什麼難度,也無需分類,直接遍歷

@Override
    public int getInDegree(int v) {
        int count = 0;
        for (int i = 1; i < maxVertex+1; i++) {
            if(i==v)
                continue;
            Iterator<VertexNode> iterator = vexList[i].listIterator(0);
            while (iterator.hasNext()){
                if(iterator.next().vertex==v){
                    count++;
                    break;
                }
            }
        }
        return count;
    }

    @Override
    public int getOutDegree(int v) {
        return vexList[v].size();
    }

鄰接矩陣實現

公式如上,只須要遍歷鄰接矩陣便可。

@Override
    public int getInDegree(int v) {
        int degree = 0;
        switch (type) {
            case DirectionWeight:
            case NoDirectionWeight:
                for (int i = 1; i < maxVertex + 1; i++) {
                    if (matrix[i][v] != INF)
                        degree++;
                }
                break;
            case DirectionNoWeight:
            case NoDirectionNoWeight:
                for (int i = 1; i < maxVertex + 1; i++) {
                    if (matrix[i][v] != 0)
                        degree++;
                }
                break;
        }
        return degree;
    }

    @Override
    public int getOutDegree(int v) {
        int degree = 0;
        switch (type) {
            case DirectionWeight:
            case NoDirectionWeight:
                for (int i = 1; i < maxVertex + 1; i++) {
                    if (matrix[v][i] != INF)
                        degree++;
                }
                break;
            case DirectionNoWeight:
            case NoDirectionNoWeight:
                for (int i = 1; i < maxVertex + 1; i++) {
                    if (matrix[v][i] != 0)
                        degree++;
                }
                break;
        }
        return degree;
    }

(4)getNeighbor系列方法

int getFirstNeighbor(int v); // none return -1
    int getNextNeighbor(int v,int v2); // none return -1

這兩個方法是用來實現後面的算法的,實現起來也很簡單

鄰接表實現

@Override
    public int getFirstNeighbor(int v) {
        if(vexList[v].size()!=0){
            return vexList[v].getFirst().vertex;
        }else
            return -1;
    }

    @Override
    public int getNextNeighbor(int v, int v2) {
        Iterator<VertexNode> iterator = vexList[v].listIterator();
        while (iterator.hasNext()){
            if(iterator.next().vertex==v2)
                if(iterator.hasNext())
                    return iterator.next().vertex;
                else
                    return -1;
        }
        return -1;
    }

鄰接矩陣實現

@Override
    public int getFirstNeighbor(int v) {
        if (type == GraphType.NoDirectionNoWeight || type == GraphType.DirectionNoWeight) {
            for (int i = 1; i < maxVertex + 1; i++) {
                if (matrix[v][i] != 0 && i != v) {
                    return i;
                }
            }
        } else {
            for (int i = 1; i < maxVertex + 1; i++) {
                if (matrix[v][i] != INF && i != v) {
                    return i;
                }
            }
        }
        return -1;
    }

    @Override
    public int getNextNeighbor(int v, int v2) {
        if (type == GraphType.NoDirectionNoWeight || type == GraphType.DirectionNoWeight) {
            for (int i = v2 + 1; i < maxVertex + 1; i++) {
                if (matrix[v][i] != 0 && i != v) {
                    return i;
                }
            }
        } else {
            for (int i = v2 + 1; i < maxVertex + 1; i++) {
                if (matrix[v][i] != INF && i != v) {
                    return i;
                }
            }
        }
        return -1;
    }

(5)getWeight方法

這個方法主要是用來做爲後續算法的接口,爲了把圖類作封裝。

通常來說只有有權圖的時候纔會用到這個方法,定義若是不存在邊的話返回INF。

鄰接表實現

@Override
    public int getWeight(int v1, int v2) {
        if (v1 < 1 || v1 > maxVertex || v2 < 1 || v2 > maxVertex) {
            System.out.println("無效輸入,退出");
            return INF;
        }
        Iterator<VertexNode> iterator = vexList[v1].listIterator();
        while (iterator.hasNext()) {
            VertexNode node = iterator.next();
            if (node.vertex == v2)
                return node.weight;
        }
        return INF;
    }

鄰接矩陣實現

@Override
    public int getWeight(int v1, int v2) {
        if (v1 < 1 || v1 > maxVertex || v2 < 1 || v2 > maxVertex) {
            System.out.println("無效輸入,退出");
            return INF;
        }
        return matrix[v1][v2];
    }

(6)深度優先搜索(DFS)

  • 思想:

    從圖中某個頂點V0出發,訪問它,而後選擇一個V0鄰接到的未被訪問的一個鄰接點V1出發深度優先遍歷圖,當遇到一個全部鄰接於它的結點都被訪問過了的結點U時,回退到前一次剛被訪問過的擁有未被訪問的鄰接點W,再從W出發深度遍歷......直到連通圖中的全部頂點都被訪問過爲止。

實現過程須要new一個boolean數組,標記節點是否訪問過

鄰接表和鄰接矩陣的實現方式一致

@Override
    public String depthFirstSearch(int v) {
        boolean[] visited = new boolean[maxVertex + 1];
        StringBuffer rs = new StringBuffer();
        rs.append(v + " → ");
        DFS(v, visited, rs);
        return rs.toString();
    }

    private void DFS(int v, boolean[] visited, StringBuffer rs) {
        visited[v] = true;
        int next = getFirstNeighbor(v);
        while (next != -1) {
            if (!visited[next]) {
                rs.append(next + " → ");
                DFS(next, visited, rs);
            }
            next = getNextNeighbor(v, next);
        }
    }

(7)廣度優先搜索(BFS)

  • 思想

    從圖中某頂點V0出發,在訪問了V0以後依次訪問v0的各個不曾訪問過的鄰接點,而後分別從這些鄰接點出發廣度優先遍歷圖,直至圖中全部頂點都被訪問到爲止

    實現過程須要new一個boolean數組,標記節點是否訪問過

    使用到了隊列結構

    鄰接表和鄰接矩陣的實現方式一致

    @Override
    	    public String breathFirstSearch(int v) {
    	        StringBuffer rs = new StringBuffer();
    	        boolean[] visited = new boolean[maxVertex+1];
    	        rs.append(v + " → ");
    	        visited[v]=true;
    	        Queue<Integer> queue = new LinkedList<>();
    	        queue.offer(v);
    	        while (!queue.isEmpty()){
    	            v = queue.poll();
    	            int next = getFirstNeighbor(v);
    	            while (next!=-1) {
    	                if (!visited[next]) {
    	                    rs.append(next + " → ");
    	                    visited[next] = true;
    	                    queue.offer(next);
    	                }
    	                next = getNextNeighbor(v,next);
    	            }
    	        }
    	        return rs.toString();
    	    }

完整代碼

LinkGraph

import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;

public class LinkGraph implements Graph {


    private LinkedList<VertexNode>[] vexList;
    private int edgeSize;
    private GraphType type;
    private int maxVertex;
    private static final int INF = 999999; // 用於有權圖的無邊表示
    Iterator<VertexNode> temp; // 用於緩存getNeighbor方法的Iterator

    public LinkGraph(GraphType type, int size) {
        vexList = new LinkedList[size + 1];
        for (int i = 1; i < size + 1; i++) {
            vexList[i] = new LinkedList();
        }
        maxVertex = size;
        edgeSize = 0;
        this.type = type;
    }

    @Override
    public boolean insertEdge(int v1, int v2, int weight) {
        if (v1 < 1 || v1 > maxVertex || v2 < 1 || v2 > maxVertex) {
            System.out.println("無效輸入,退出");
            return false;
        }
        boolean contain = false;
        switch (type) {
            case DirectionNoWeight:
                weight = 1;
            case DirectionWeight:
                for (VertexNode vex : vexList[v1]) {
                    if (vex.vertex == v2)
                        contain = true;
                }
                if (!contain)
                    edgeSize++;
                vexList[v1].add(new VertexNode(v2, weight));
                break;
            case NoDirectionNoWeight:
                weight = 1;
            case NoDirectionWeight:
                for (VertexNode vex : vexList[v1]) {
                    if (vex.vertex == v2)
                        contain = true;
                }
                if (!contain)
                    edgeSize++;
                vexList[v1].add(new VertexNode(v2, weight));
                vexList[v2].add(new VertexNode(v1, weight));
                break;
        }
        return true;
    }


    @Override
    public boolean deleteEdge(int v1, int v2) {
        if (v1 < 1 || v1 > maxVertex || v2 < 1 || v2 > maxVertex) {
            System.out.println("無效輸入,退出");
            return false;
        }
        Iterator<VertexNode> iterator;
        switch (type) {
            case DirectionNoWeight:
            case DirectionWeight:
                iterator = vexList[v1].listIterator(0);
                while (iterator.hasNext()) {
                    if (iterator.next().vertex == v2) {
                        iterator.remove();
                        edgeSize--;
                        break;
                    }
                }
                break;
            case NoDirectionWeight:
            case NoDirectionNoWeight:
                iterator = vexList[v1].listIterator(0);
                while (iterator.hasNext()) {
                    if (iterator.next().vertex == v2) {
                        iterator.remove();
                        edgeSize--;
                        iterator = vexList[v2].listIterator(0);
                        while (iterator.hasNext()) {
                            if (iterator.next().vertex == v1) {
                                iterator.remove();
                                edgeSize--;
                                break;
                            }
                            break;
                        }
                    }
                    break;
                }
        }
        return true;
    }

    @Override
    public int getDegree(int v) {
        if (type == GraphType.NoDirectionWeight || type == GraphType.NoDirectionNoWeight)
            return getOutDegree(v); // 由於算起來比GetInDegree快
        else
            return getInDegree(v) + getOutDegree(v);
    }

    @Override
    public int getInDegree(int v) {
        int count = 0;
        for (int i = 1; i < maxVertex+1; i++) {
            if(i==v)
                continue;
            Iterator<VertexNode> iterator = vexList[i].listIterator(0);
            while (iterator.hasNext()){
                if(iterator.next().vertex==v){
                    count++;
                    break;
                }
            }
        }
        return count;
    }

    @Override
    public int getOutDegree(int v) {
        return vexList[v].size();
    }

    @Override
    public String depthFirstSearch(int v) {
        boolean[] visited = new boolean[maxVertex + 1];
        StringBuffer rs = new StringBuffer();
        rs.append(v + " → ");
        DFS(v, visited, rs);
        return rs.toString();
    }

    private void DFS(int v, boolean[] visited, StringBuffer rs) {
        visited[v] = true;
        int next = getFirstNeighbor(v);
        while (next != -1) {
            if (!visited[next]) {
                rs.append(next + " → ");
                DFS(next, visited, rs);
            }
            next = getNextNeighbor(v, next);
        }
    }

    @Override
    public String breathFirstSearch(int v) {
        StringBuffer rs = new StringBuffer();
        boolean[] visited = new boolean[maxVertex+1];
        rs.append(v + " → ");
        visited[v]=true;
        Queue<Integer> queue = new LinkedList<>();
        queue.offer(v);
        while (!queue.isEmpty()){
            v = queue.poll();
            int next = getFirstNeighbor(v);
            while (next!=-1) {
                if (!visited[next]) {
                    rs.append(next + " → ");
                    visited[next] = true;
                    queue.offer(next);
                }
                next = getNextNeighbor(v,next);
            }
        }
        return rs.toString();
    }

    @Override
    public GraphType getGraphType() {
        return type;
    }

    @Override
    public int getFirstNeighbor(int v) {
        if(vexList[v].size()!=0){
            return vexList[v].getFirst().vertex;
        }else
            return -1;
    }

    @Override
    public int getNextNeighbor(int v, int v2) {
        Iterator<VertexNode> iterator = vexList[v].listIterator();
        while (iterator.hasNext()){
            if(iterator.next().vertex==v2)
                if(iterator.hasNext())
                    return iterator.next().vertex;
                else
                    return -1;
        }
        return -1;
    } 
    
    @Override
    public int getSize() {
        return maxVertex;
    }

    @Override
    public int getWeight(int v1, int v2) {
        if (v1 < 1 || v1 > maxVertex || v2 < 1 || v2 > maxVertex) {
            System.out.println("無效輸入,退出");
            return INF;
        }
        Iterator<VertexNode> iterator = vexList[v1].listIterator();
        while (iterator.hasNext()) {
            VertexNode node = iterator.next();
            if (node.vertex == v2)
                return node.weight;
        }
        return INF;
    }

    private class VertexNode {
        int vertex;
        int weight;

        VertexNode(int vex, int weight) {
            vertex = vex;
            this.weight = weight;
        }

        VertexNode(int vex) {
            vertex = vex;
            this.weight = 1;
        }
    }
    
    @Override
    public int getEdgeSize() {
        return edgeSize;
    }
}

MatrixGraph

import java.util.LinkedList;
import java.util.Queue;

public class MatrixGraph implements Graph {

    public static void main(String[] args) {
        Graph graph = new MatrixGraph(GraphType.DirectionWeight, 10);
        graph.insertEdge(1, 3, 1);
        graph.insertEdge(4, 3, 1);
        graph.insertEdge(3, 8, 1);
        graph.insertEdge(6, 3, 1);
        graph.insertEdge(8, 9, 1);
        System.out.println(graph.getInDegree(7));
        System.out.println(graph.getOutDegree(3));
        System.out.println(graph.getDegree(3));
    }

    private int[][] matrix;
    private int edgeSize;
    private GraphType type;
    private int maxVertex;
    private static final int INF = 999999; // 用於有權圖的無邊表示

    public MatrixGraph(GraphType type, int size) {
        matrix = new int[size + 1][size + 1];
        maxVertex = size;
        edgeSize = 0;
        this.type = type;
        switch (type) {
            case DirectionWeight:
            case NoDirectionWeight:
                for (int i = 0; i < size + 1; i++) {
                    for (int j = 0; j < size + 1; j++) {
                        matrix[i][j] = INF;
                    }
                }
                break;
            case DirectionNoWeight:
            case NoDirectionNoWeight:
                for (int i = 0; i < size + 1; i++) {
                    for (int j = 0; j < size + 1; j++) {
                        matrix[i][j] = 0;
                    }
                }
                break;
        }
    }

      @Override
    public boolean insertEdge(int v1, int v2, int weight) {
        if (v1 < 1 || v1 > maxVertex || v2 < 1 || v2 > maxVertex) {
            System.out.println("無效輸入,退出");
            return false;
        }
        switch (type) {
            case DirectionNoWeight:
                if (matrix[v1][v2] == 0)
                    edgeSize++;
                matrix[v1][v2] = 1;
                break;
            case NoDirectionNoWeight:
                if (matrix[v1][v2] == 0)
                    edgeSize++;
                matrix[v1][v2] = 1;
                matrix[v2][v1] = 1;
                break;
            case DirectionWeight:
                if (matrix[v1][v2] == INF)
                    edgeSize++;
                matrix[v1][v2] = weight;
                break;
            case NoDirectionWeight:
                if (matrix[v1][v2] == INF)
                    edgeSize++;
                matrix[v1][v2] = weight;
                matrix[v2][v1] = weight;
                break;
        }
        return true;
    }

    @Override
    public boolean deleteEdge(int v1, int v2) {
        if (v1 < 1 || v1 > maxVertex || v2 < 1 || v2 > maxVertex) {
            System.out.println("無效輸入,退出");
            return false;
        }
        switch (type) {
            case DirectionNoWeight:
                if (matrix[v1][v2] != 0)
                    edgeSize--;
                matrix[v1][v2] = 0;
                break;
            case NoDirectionNoWeight:
                if (matrix[v1][v2] != 0)
                    edgeSize--;
                matrix[v1][v2] = 0;
                matrix[v2][v1] = 0;
                break;
            case DirectionWeight:
                if (matrix[v1][v2] != INF)
                    edgeSize--;
                matrix[v1][v2] = INF;
                break;
            case NoDirectionWeight:
                if (matrix[v1][v2] != INF)
                    edgeSize--;
                matrix[v1][v2] = INF;
                matrix[v2][v1] = INF;
                break;
        }
        return true;
    }


    @Override
    public int getDegree(int v1) {
        if (type == GraphType.NoDirectionWeight || type == GraphType.NoDirectionNoWeight)
            return getInDegree(v1);
        else
            return getInDegree(v1) + getOutDegree(v1);
    }

    @Override
    public int getInDegree(int v) {
        int degree = 0;
        switch (type) {
            case DirectionWeight:
            case NoDirectionWeight:
                for (int i = 1; i < maxVertex + 1; i++) {
                    if (matrix[i][v] != INF)
                        degree++;
                }
                break;
            case DirectionNoWeight:
            case NoDirectionNoWeight:
                for (int i = 1; i < maxVertex + 1; i++) {
                    if (matrix[i][v] != 0)
                        degree++;
                }
                break;
        }
        return degree;
    }

    @Override
    public int getOutDegree(int v) {
        int degree = 0;
        switch (type) {
            case DirectionWeight:
            case NoDirectionWeight:
                for (int i = 1; i < maxVertex + 1; i++) {
                    if (matrix[v][i] != INF)
                        degree++;
                }
                break;
            case DirectionNoWeight:
            case NoDirectionNoWeight:
                for (int i = 1; i < maxVertex + 1; i++) {
                    if (matrix[v][i] != 0)
                        degree++;
                }
                break;
        }
        return degree;
    }

    @Override
    public String depthFirstSearch(int v) {
        boolean[] visited = new boolean[maxVertex + 1];
        StringBuffer rs = new StringBuffer();
        rs.append(v + " → ");
        DFS(v, visited, rs);
        return rs.toString();
    }

    private void DFS(int v, boolean[] visited, StringBuffer rs) {
        visited[v] = true;
        int next = getFirstNeighbor(v);
        while (next != -1) {
            if (!visited[next]) {
                rs.append(next + " → ");
                DFS(next, visited, rs);
            }
            next = getNextNeighbor(v, next);
        }
    }

    @Override
    public String breathFirstSearch(int v) {
        StringBuffer rs = new StringBuffer();
        boolean[] visited = new boolean[maxVertex+1];
        rs.append(v + " → ");
        visited[v]=true;
        Queue<Integer> queue = new LinkedList<>();
        queue.offer(v);
        while (!queue.isEmpty()){
            v = queue.poll();
            int next = getFirstNeighbor(v);
            while (next!=-1) {
                if (!visited[next]) {
                    rs.append(next + " → ");
                    visited[next] = true;
                    queue.offer(next);
                }
                next = getNextNeighbor(v,next);
            }
        }
        return rs.toString();
    }

    @Override
    public GraphType getGraphType() {
        return type;
    }

    @Override
    public int getFirstNeighbor(int v) {
        if (type == GraphType.NoDirectionNoWeight || type == GraphType.DirectionNoWeight) {
            for (int i = 1; i < maxVertex + 1; i++) {
                if (matrix[v][i] != 0 && i != v) {
                    return i;
                }
            }
        } else {
            for (int i = 1; i < maxVertex + 1; i++) {
                if (matrix[v][i] != INF && i != v) {
                    return i;
                }
            }
        }
        return -1;
    }

    @Override
    public int getNextNeighbor(int v, int v2) {
        if (type == GraphType.NoDirectionNoWeight || type == GraphType.DirectionNoWeight) {
            for (int i = v2 + 1; i < maxVertex + 1; i++) {
                if (matrix[v][i] != 0 && i != v) {
                    return i;
                }
            }
        } else {
            for (int i = v2 + 1; i < maxVertex + 1; i++) {
                if (matrix[v][i] != INF && i != v) {
                    return i;
                }
            }
        }
        return -1;
    }
    
    @Override
    public int getSize() {
        return maxVertex;
    }

    @Override
    public int getWeight(int v1, int v2) {
        if (v1 < 1 || v1 > maxVertex || v2 < 1 || v2 > maxVertex) {
            System.out.println("無效輸入,退出");
            return INF;
        }
        return matrix[v1][v2];
    }
    
    @Override
    public int getEdgeSize() {
        return edgeSize;
    }
}
相關文章
相關標籤/搜索