(圖)html
(圖)
node
鄰接矩陣:使用布爾數組來實現存儲邊。將存在邊的位置記錄爲true,無位置的記錄爲false。對於一個無向圖,其存儲結果是一個對稱矩陣。可是對於有向圖來講,由於邊的單向性,結果將不一樣。git
問題1理解:首先打眼一看,彷佛兩個方法沒什麼區別。BFS至關因而從第一個頂點開始遍歷完其全部的鄰頂點的鄰頂點再進行下一個的遍歷。DFS相似於前序遍歷。 經過對課本代碼的分析。找出了幾個關鍵部分代碼。第一點,使用了不一樣的數據結構對其進行存儲。BFS使用了隊列的方式。DFS使用了棧進行存儲。下面就詳細的進行分析。先看BFS的代碼。算法
while (!traversalQueue.isEmpty()) { x = traversalQueue.dequeue(); resultList.addToRear(vertices[x.intValue()]); //Find all vertices adjacent to x that have not been visited // and queue them up for (int i = 0; i < numVertices; i++) { if (adjMatrix[x.intValue()][i] && !visited[i]) { traversalQueue.enqueue(new Integer(i)); visited[i] = true; } } }
首先,先聲明,書上的方法均是是基於鄰接矩陣實現的。具體來說也就是兩個布爾數組來肯定頂點與頂底之間是否有邊。將頂點進入隊列後,再取出放入列表之中。而後根據鄰接矩陣來判斷邊,也就是找出全部的鄰接頂點。依次存入隊列之中。當找到全部的鄰接頂點後。將第一個進入隊列的頂底取出,找出其全部的鄰接頂點。以後再進行下一個頂點的鄰接頂點的查詢。經過隊列先進先出的順序,將全部頂點按照相似於樹的先序遍歷的方法儲存起來。那麼,如何防止出現重複的結點呢?創建的boolean型的visited數組就能夠解決這個問題,初始化時全部結點都是false也就是未被訪問。當訪問到一個頂點後,將其標記爲true。當下一次再訪問到這個頂點後。就進行跳過。編程
while (!traversalStack.isEmpty()) { x = traversalStack.peek(); found = false; //Find a vertex adjacent to x that has not been visited // and push it on the stack for (int i = 0; (i < numVertices) && !found; i++) { if (adjMatrix[x.intValue()][i] && !visited[i]) { traversalStack.push(new Integer(i)); resultList.addToRear(vertices[i]); visited[i] = true; found = true; } } if (!found && !traversalStack.isEmpty()) traversalStack.pop(); }
衆所周知,棧是後進先出的。那麼,若是以頂點V開始,它的第一個鄰頂點爲U。那麼它入棧,緊接着尋找U的第一個鄰頂點,而後將其入棧。每次使用peek方法獲取當前棧頂元素,也就是上一個頂點的第一個鄰頂點。當找不到時,將其彈出。就比如一棵樹,當把這一棵子樹的全部結點找完後,就去下一棵子樹找。同理,循環會將已經都訪問過的頂點彈出棧,直到找到沒有訪問過鄰頂點的頂點。按照這個順序,將頂點按照深度優先的順序存入列表中。數組
int[] pathLength = new int[numVertices]; int[] predecessor = new int[numVertices];
以後根據放入的順序進行遍歷,若是與頂點有邊,那麼,將其存入,以後用隊列,將其存儲。若是隻是須要具體的數字,咱們直接將其對應的索引對應的數字返回便可。數據結構
while (!traversalQueue.isEmpty() && (index != targetIndex)) { index = (traversalQueue.dequeue()).intValue(); //Update the pathLength for each unvisited vertex adjacent // to the vertex at the current index. for (int i = 0; i < numVertices; i++) { if (adjMatrix[index][i] && !visited[i])// { pathLength[i] = pathLength[index] + 1; predecessor[i] = index; traversalQueue.enqueue(new Integer(i)); visited[i] = true; } } }
可是,咱們不妨再將其順序返回,使得其更加直觀。經過以前對部分方法的分析咱們不難發現,對於這種非線性數據結構,有時使用隊列來達到層序遍歷,而使用棧達到前序遍歷(後序遍歷)這時,咱們就用棧(後進先出)來實現。ide
StackADT<Integer> stack = new LinkedStack<Integer>(); index = targetIndex; stack.push(new Integer(index)); do { index = predecessor[index]; stack.push(new Integer(index)); } while (index != startIndex); while (!stack.isEmpty()) resultList.addToRear(((Integer)stack.pop()));
public static final double POSITIVE_INFINITY = 1.0 / 0.0;
就是無窮大了,它被定義於Double中,能夠直接調用。而後,首先對目前已有的「非0(不是它本身)非-1(二者之間有邊)。在這個基礎上,選出最小的值,存入列表之中。以後,用最小值的索引值來繼續向下遍歷。換句話說,對於dist數組中存取數據爲無窮大的(也就是計算出未直接與初頂點相連的間接權重)學習
for (int i = 0; i < numVertices; i++) { flag[i] = false; dist[i] = adjMatrix[start][i]; }
for (int j = 0; j < numVertices; j++) { if (flag[j] == false && dist[j] < min && dist[j] != -1 && dist[j] != 0) { min = dist[j]; k = j; } }
這裏的k就是最小權的索引值。每次都選擇最小的權重邊做爲路徑。而後重複這個過程。最終,整個disc數組的每一個索引對應的就是從初頂點到該對應索引的最短權重路徑。咱們根據須要,取出便可。編碼
for (int j = 0; j < numVertices; j++) { if (adjMatrix[k][j] != -1&&dist[j]!= -1) { double temp = (adjMatrix[k][j] == Double.POSITIVE_INFINITY ? Double.POSITIVE_INFINITY : (min + adjMatrix[k][j])); if (flag[j] == false && (temp < dist[j])) { dist[j] = temp; } } } } return dist[end];
對於堆,插入元素時,爲了知足其徹底樹的定義,當一層未滿時,優先將元素放至左孩子位置,如左孩子填滿,則放至右孩子處。若是一層滿。則放在下一層的第一個位置。
圖的狀況有不少種,有向和無向,有權重和無權重,遍歷方法也比較難懂,須要繼續學習
代碼中值得學習的或問題:
代碼寫的很規範,思路很清晰,繼續加油!
代碼行數(新增/累積) | 博客量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 | |
第一週 | 0/0 | 1/1 | 3/3 | |
第二週 | 409/409 | 1/2 | 5/8 | |
第三週 | 1174/1583 | 1/3 | 10/18 | |
第四周 | 1843/3426 | 2/5 | 10/28 | |
第五週 | 539/3965 | 2/7 | 20/48 | |
第六週 | 965/4936 | 1/8 | 20/68 | |
第七週 | 766/5702 | 1/9 | 20/88 | |
第八週 | 1562/7264 | 2/11 | 20/108 | |
第九周 | 2016/9280 | 1/12 | 20/128 |