20162320劉先潤大二 實驗四 圖及應用
阿新 • • 發佈:2017-11-26
進入 關系 步驟 計算機 dijk i++ div rst 例子
實驗涉及代碼
AMatrix、AMatrixTest、CrossList、CrossListTest、Road、RoadTest
圖的實現與應用-1
實驗目的:用鄰接矩陣實現無向圖(邊和頂點都要保存),實現在包含添加和刪除結點的方法,添加和刪除邊的方法,size(),isEmpty(),廣度優先叠代器,深度優先叠代器
實現思路:實現鄰接矩陣得確定一個表示方法,對於結點於結點之間的關系得使用二元數組來實現。由於無向圖的鄰接矩陣是對稱矩陣,且其左上角到右下角的對角線上值為零,這是其中應用的一條性質。所以根據實現步驟可以得出如下偽代碼:
確定圖的頂點個數和邊的個數; 輸入頂點信息存儲在一維數組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;
}
}
}
}
}
}
實驗測試:創建測試用圖進行測試
20162320劉先潤大二 實驗四 圖及應用