20162320劉先潤大二 實驗四 圖及應用

實驗涉及代碼

AMatrixAMatrixTestCrossListCrossListTestRoadRoadTestjava


圖的實現與應用-1

實驗目的:用鄰接矩陣實現無向圖(邊和頂點都要保存),實如今包含添加和刪除結點的方法,添加和刪除邊的方法,size(),isEmpty(),廣度優先迭代器,深度優先迭代器git

實現思路:實現鄰接矩陣得肯定一個表示方法,對於結點於結點之間的關係得使用二元數組來實現。因爲無向圖的鄰接矩陣是對稱矩陣,且其左上角到右下角的對角線上值爲零,這是其中應用的一條性質。因此根據實現步驟能夠得出以下僞代碼:

 肯定圖的頂點個數和邊的個數; 
 輸入頂點信息存儲在一維數組vertex中;  
 初始化鄰接矩陣; 
 依次輸入每條邊存儲在鄰接矩陣中;     
 輸入邊依附的兩個頂點的序號i, j; 
 將鄰接矩陣的第i行第j列的元素值置爲1;   
 將鄰接矩陣的第j行第i列的元素值置爲1;

實驗過程:

  • 1.建立二位數組,並肯定頂點和邊的變量,得出size()isEmpty()的方法,返回二維數組的大小和斷定二維數組是否爲空。
  • 2.插入和刪除邊和結點,關於結點是輸入點的名稱,插入邊則是輸入邊相連的兩點的座標肯定其位置以及相應的權值。若刪除邊和結點,則是把兩點的座標修改成0和0,並將其對應的數目減一則刪除成功。
public void addVertex(Object vertex) {
        vertexList.add(vertexList.size(),vertex);
    }

 public void insertEdge(int v1,int v2,int weight) {
        edges[v1][v2]=weight;
        numOfEdges++;
    }
 public void deleteEdge(int v1,int v2) {
        edges[v1][v2]=0;
        numOfEdges--;
    }
  • 3.獲得下一個鄰接結點的座標,經過創建一個循環,查找到二維數組中索引維度下一個索引的位置,若越界則另外一個索引維度加一獲得返回值。
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;
    }
  • 4.廣度遍歷方法,過程是對每一層節點依次訪問,訪問完一層進入下一層,並且每一個節點只能訪問一次。對於上面的例子來講,廣度優先遍歷的 結果是:A,B,C,D,E,F,G,H,I(假設每層節點從左到右訪問)。首先私有函數廣度遍歷,建立一個隊列保存結點,訪問第i個結點並讓其入隊列.而後訪問該結點,而後設置結點標記爲已經被訪問,而後入隊列,並尋找下一個臨接結點。
private void broadFirstSearch(boolean[] isVisited, int i) {
        int a, b;
        LinkedList queue = new LinkedList();
        System.out.print(getValueByIndex(i) + "  ");
        isVisited[i] = true;
        queue.addLast(i);
        while (!queue.isEmpty()) {
            a = ((Integer) queue.removeFirst()).intValue();
            b = getFirstNeighbor(a);
            while (b != -1) {
                if (!isVisited[b]) {
                    System.out.print(getValueByIndex(b) + "  ");
                    isVisited[b] = true;
                    queue.addLast(b);
                }
                b = getNextNeighbor(a, b);
            }
        }
    }

    public void broadFirstSearch() {
        for(int i = 0; i< size(); i++) {
            if(!isVisited[i]) {
                broadFirstSearch(isVisited, i);
            }
        }
    }
  • 5.深度優先遍歷,對每個可能的分支路徑深刻到最底層,而且每一個節點只能訪問一次。首先訪問該結點並將其打印,而後將其設置爲已訪問狀態,若是訪問到結點爲二維數組盡頭則從沒有遍歷的結點訪問,以此循環下去。
public void depthFirstSearch(boolean[] isVisited,int  i) {
        System.out.print(getValueByIndex(i)+"  ");
        isVisited[i]=true;
        int w=getFirstNeighbor(i);//
        while (w!=-1) {
            if (!isVisited[w]) {
                depthFirstSearch(isVisited,w);
            }
            w=getNextNeighbor(i, w);
        }
    }

    public void depthFirstSearch() {
        for(int i = 0; i< size(); i++) {
            if (!isVisited[i]) {
                depthFirstSearch(isVisited,i);
            }
        }
    }

實驗測試:建立如圖所示的圖進行測試


圖的實現與應用-2

實驗目的:用十字鏈表實現無向圖(邊和頂點都要保存),實如今包含添加和刪除結點的方法,添加和刪除邊的方法,size(),isEmpty(),廣度優先迭代器,深度優先迭代器算法

實驗思路:十字鏈表的結構能夠當作是將有向圖的鄰接表和逆鄰接表結合起來獲得的。用鏈表模擬矩陣的行,而後再構造表明列的鏈表,將每一行中的元素節點插入到對應的列中去。

實驗過程:

  • 1.首先定義邊和結點的類,提供一個輸入方法,關於結點要設置先入先出,邊則須要添加同入弧和同出弧變量,以方便指向。最後入結點和出結點指向對應的邊,因此邊鏈表須要有四個區域。
public static class Vertex<E,T>  {
        E data;
        Edge<T> firstIn;
        Edge<T> firstOut;

        public Vertex(E data) {
            this.data = data;
        }
    }

    public static class Edge<E> {
        E data;
        int From;
        int To;
        Edge<E> SameFromVertex;
        Edge<E> SameToVertex;

 public Edge(E data, int From, int To) {
            this.data = data;
            this.From = From;
            this.To = To;
        }
    }
  • 2.添加、刪除邊和點,首先建立兩個收集集合與邊的變量,用來統計兩者的總數。添加點直接使用鏈表的添加方法並讓結點總數加一便可,而刪除點則須要不只僅刪除結點,還須要刪除與此個結點相關的全部邊的指向。添加邊是須要將入結點插入到頂點或者插入到邊的同入弧,若是該頂點沒有入弧,則將結點指向爲Null,最後添加邊的總數。刪除邊則直接使用鏈表的remove方法便可。
public void removeV(Vertex<Integer, Integer> vex){
        for (int index = 0; index< AllEdge.size(); index++){
            if (AllEdge.get(index).From== AllVertex.indexOf(vex)|| AllEdge.get(index).To== AllVertex.indexOf(vex)){
                AllEdge.remove(index);
                index=0;
            }
        }
        AllVertex.remove(vex);
    }

 public void addE(Edge<Integer> edge) {
        Edge<Integer> edge1 = new Edge<>(edge.data,edge.From,edge.To);
        Edge<Integer> edge2 = new Edge<>(edge.data,edge.From,edge.To);
        AllEdge.add(edge);
        int fromVertexIndex = edge.From;
        int toVertexIndex = edge.To;
        Vertex<Integer, Integer> fromVertex = AllVertex.get(fromVertexIndex);
        Vertex<Integer, Integer> toVertex = AllVertex.get(toVertexIndex);
        if (fromVertex.firstOut == null) {
            fromVertex.firstOut = edge1;
        } else {
            Edge<Integer> tempEdge = fromVertex.firstOut;
            while (tempEdge.SameFromVertex != null) {
                tempEdge = tempEdge.SameFromVertex;
                System.out.println();
            }
            tempEdge.SameFromVertex = edge1;
        }
        if (toVertex.firstIn == null) {
            toVertex.firstIn = edge2;
        } else {
            Edge<Integer> tempEdge = toVertex.firstIn;
            while (tempEdge.SameToVertex != null) {
                tempEdge = tempEdge.SameToVertex;
            }
            tempEdge.SameToVertex = edge2;
        }
        System.out.println();
    }
  • 3.添加size()方法須要將添加的結點保存至一個集合,不然沒法獲得返回值。
static List<Vertex<Integer,Integer>> AllVertex = new ArrayList<>();
public int size(){
        return AllVertex.size();
    }
  • 4.廣度以及深度遍歷,深度遍歷實現方法:首先選擇一個頂點入棧,若是棧非空棧,則出棧並訪問出棧元素,並標示爲已訪問。而後將出棧頂點的鄰接頂點(要求未被訪問過)所有入棧。重複前一步驟直至沒有能夠訪問到的頂點。廣度遍歷方法:首先選擇一個未被訪問的頂點入隊。若是隊列非空隊列,則出隊並訪問,而後標記爲已被訪問。並將出隊頂點的鄰接頂點都入隊。而後重複前一個步驟直至沒有能夠訪問的頂點。(詳細代碼見代碼鏈接)

實驗測試:建立一個測試圖進行測試,如圖所示


圖的實現與應用-3

實驗目的:建立計算機網絡路由系統,輸入網絡中點到點的線路,以及每條線路使用的費用,系統輸出網絡中各點之間最便宜的路徑,指出不相通的全部位置。數組

實驗思路:該實驗須要求出最短路徑,能夠經過求單源最短路徑,使用Dijkstra算法。

實驗過程:

  • 1.建立無向圖的變量表示,存儲全部頂點的一維數組,存儲圖中頂點與邊關係的二維數組,對數組進行初始化,頂點間沒有邊關聯的值爲int類型最大值
public Road(boolean graphType, boolean method, int size) {
        this.graphType = graphType;
        this.method = method;
        this.NumVertex = 0;
        this.matrix = size;

        if (this.method) {
            visited = new boolean[matrix];
            vertexesArr = new Object[matrix];
            edgesMatrix = new int[matrix][matrix];

            for (int row = 0; row < edgesMatrix.length; row++) {
                for (int column = 0; column < edgesMatrix.length; column++) {
                    edgesMatrix[row][column] = MAX_VALUE;
                    System.out.print("");
                }
            }
        }
    }
  • 2.求單個點到其餘點的最便宜路徑長度,即求最小權值路徑。能夠一開始假設直達路徑爲最短路徑,在這種狀況下的最後經由點就是出發點。初始數組時起點v0訪問集合,表示v0 到v0的最短路徑已經找到
    。而後下來假設經由一個點中轉到達其他各點,會權值更小近些並驗證之,而後重複該過程,直到列舉完全部可能的點。建立一個循環將最短路徑的權值記錄而且打印出來。
public void Dijkstra(int v0) {
        int[] dist = new int[matrix];
        int[] prev = new int[matrix];

        for (int i = 0; i < NumVertex; i++) {
            dist[i] = edgesMatrix[v0][i];
            visited[i] = false;
            if (i != v0 && dist[i] < MAX_VALUE)
                prev[i] = v0;
            else
                prev[i] = -1;
        }

        visited[v0] = true;
        int minDist;
        int v = 0;
        for (int i = 1; i < NumVertex; i++) {
            minDist = MAX_VALUE;

            for (int j = 0; j < NumVertex; j++) {
                if ((!visited[j]) && dist[j] < minDist) {
                    v = j;
                    minDist = dist[j];
                }
            }
            visited[v] = true;

            for (int j = 0; j < NumVertex; j++) {
                if ((!visited[j]) && edgesMatrix[v][j] < MAX_VALUE) {
                    if (minDist + edgesMatrix[v][j] <= dist[j]) {
                        dist[j] = minDist + edgesMatrix[v][j];
                        prev[j] = v;
                    }

                }
            }

        }

        for (int i = 0; i < matrix; i++) {
            if (dist[i] > 1000) {
                dist[i] = 0;
            }
            System.out.println(vertexesArr[v0] + "到" + vertexesArr[i] + "的最短路徑是:" + dist[i]);
        }
    }
  • 3.求出最短的路徑可使用Dijkstra算法。建立一個隊列,經過步驟2求出最便宜權值的路徑方法記錄其通過而且標記的結點,將其輸出出去,而且訪問未標記的結點獲得Dijkstra算法的最短路徑。
public void DRoad(int v0) {
        Queue<Integer> queue = new LinkedList<Integer>();
        for (int i = 0; i < NumVertex; i++) {
            visited[i] = false;
        }

        for (int i = 0; i < NumVertex; i++) {
            if (!visited[i]) {
                queue.add(i);
                visited[i] = true;
                while (!queue.isEmpty()) {
                    int row = queue.remove();
                    System.out.print(vertexesArr[row] + "→");
                    for (int k = getMin(row); k >= 0; k = getMin(row)) {
                        if (!visited[k]) {
                            queue.add(k);
                            visited[k] = true;
                        }
                    }
                }
            }
        }
    }

實驗測試:建立測試用圖進行測試


相關文章
相關標籤/搜索