20172303 2018-2019-1《程序設計與數據結構》深度優先遍歷

20172303 2018-2019-1《程序設計與數據結構》深度優先遍歷

遍歷

  • 圖的遍歷是指從圖中的某一頂點出發,按照必定的策略訪問圖中的每個頂點。固然,每一個頂點有且只能被訪問一次。
  • 在圖的遍歷中,深度優先和廣度優先是最常使用的兩種遍歷方式。這兩種遍歷方式對無向圖和有向圖都是適用的,而且都是從指定的頂點開始遍歷的。

深度優先遍歷

簡單介紹

  • 深度優先遍歷也叫深度優先搜索(Depth First Search)。
  • 遍歷規則:不斷地沿着頂點的深度方向遍歷。頂點的深度方向是指它的鄰接點方向。具體點,給定一圖G=<V,E>,用visited[i]表示頂點i的訪問狀況,則初始狀況下全部的visited[i]都爲false。假設從頂點V0開始遍歷,則下一個遍歷的頂點是V0的第一個鄰接點Vi,接着遍歷Vi的第一個鄰接點Vj,直到全部的頂點都被訪問過。
  • 所謂的第一個是指在某種存儲結構中(鄰接矩陣、鄰接表),全部鄰接點中存儲位置最近的,一般指的是下標最小的或元素最小的。

遍歷過程

  • 在遍歷的過程當中有兩種狀況常常出現:
    • 某個頂點的鄰接點都已被訪問過的狀況,此時需回溯已訪問過的頂點。
    • 圖不連通,全部的已訪問過的頂點都已回溯完了,仍找不出未被訪問的頂點。此時需從下標0開始檢測visited[i],找到未被訪問的頂點i,從i開始新一輪的深度搜索。
  • 舉個例子
    • V0->V1->V3->V2->V4
    • V1->V3->V0->V2->V4
    • V2->V0->V1->V3->V4
    • V3->V0->V1->V2->V4
    • V4->V2->V0->V1->V3

代碼分析

  • 深度優先遍歷——使用一個棧和一個無序列表來實現,棧用於管理遍歷,無序列表用於存儲遍歷結果
    • 第一步:起始頂點進入棧。
    • 第二步:從棧中取出起始頂點加入無序列表的末端,標記爲已訪問,讓與該頂點相連的頂點加入棧中。
    • 第三步:重複第二步的操做,每次取出棧頂元素加入無序列表,把頂點標記爲已訪問,直至棧爲空。
  • 鄰接矩陣實現的圖中的深度優先遍歷
public Iterator<T> iteratorDFS(int startIndex)
    {
        Integer x;
        boolean found;
        StackADT<Integer> traversalStack = new LinkedStack<Integer>();
        UnorderedListADT<T> resultList = new ArrayUnorderedList<T>();
        boolean[] visited = new boolean[numVertices];// 標記判斷是否訪問,防止出現重複遍歷的狀況

        if (!indexIsValid(startIndex)) {
            throw new ElementNotFoundException("Graph");
            // return resultList.iterator();
        }

        //  numVertices用於記錄頂點的個數
        for (int i = 0; i < numVertices; i++) {
            visited[i] = false;
        }
        
        traversalStack.push(new Integer(startIndex));
        resultList.addToRear(vertices[startIndex]);
        visited[startIndex] = true;
        
        // 開始循環,每次把棧頂元素添加到resultList中,將與首頂點鏈接的還未進入隊列的頂點加入棧
        while (!traversalStack.isEmpty())
        {
            x = traversalStack.peek();
            found = false;

            //找到一個與x相鄰的沒有訪問過的頂點,並將其入棧
            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();
            }
        }
        return new GraphIterator(resultList.iterator());
    }
  • 鄰接列表實現的圖中的深度優先遍歷
public Iterator iteratorBFS(int startIndex){
        Integer x;
        QueueADT<Integer> traversalQueue = new LinkedQueue<Integer>();
        UnorderedListADT resultList = new ArrayUnorderedList();

        // 若所給索引值無效,拋出錯誤
        if (!indexIsValid(startIndex)){
            throw new ElementNotFoundException("Graph");
        }

        // 設置每一個頂點是否被訪問,初始設置爲未訪問
        boolean[] visited = new boolean[numVertices];
        for (int i = 0;i < numVertices;i++){
            visited[i] = false;
        }

        // 起始頂點進入隊列,並標記爲已訪問
        traversalQueue.enqueue(startIndex);
        visited[startIndex] = true;

        // 開始循環,每次把隊列中的首頂點添加到resultList中,將與首頂點鏈接的還未進入隊列的頂點加入隊列,並標記爲已訪問
        while (!traversalQueue.isEmpty()){
            x = traversalQueue.dequeue();
            resultList.addToRear(vertices.get(x).getElement());

            for (int i = 0;i < numVertices;i++){
                if (hasEdge(x,i) && !visited[i]){
                    traversalQueue.enqueue(i);
                    visited[i] = true;
                    a++;
                }
            }
        }
        return new GraphIterator(resultList.iterator());
    }
    
    // 判斷兩頂點之間是否有邊
    public boolean hasEdge(int a,int b){
        if (a == b){
            return false;
        }
        VerticeNode vertex1 = vertices.get(a);
        VerticeNode vertex2 = vertices.get(b);
        while (vertex1 != null){
            if (vertex1.getElement() == vertex2.getElement()){
                return true;
            }
            vertex1 = vertex1.getNext();
        }
        return false;
    }

一個例子

參考資料

相關文章
相關標籤/搜索