天天看點

圖的相關算法參考文獻

上一次我們介紹了圖的相關的資料結構,今天我們來介紹圖的有關算法。

接下來我将以如下的順序介紹算法:1.圖的周遊(廣度和深度)2.最小生成樹 3.最短路徑 4.拓撲排序 5.關鍵路徑

一、圖的周遊

1.基本思路

1).圖的周遊:從圖中某一個頂點出發周遊途中其餘結點,每一 個頂點僅僅被周遊 一次。
2).基本思路
    (1)樹有四種周遊方式,因為根結點隻有一個。而圖的複雜情況是順着一個 
       點向下尋找,很有可能又找回到自己,容易形成回路造成死循環。
    (2)是以要設定一個數組visited[n],n是圖中頂點的個數,初值為0,當該頂  
       點被周遊後,修改數組元素值為1.
    (3)基于上面的思想,形成兩個周遊方案:深度優先周遊和廣度優先周遊。
           

2.深度優先周遊

深度優先周遊,就是從初始通路結點出發,我們知道初始通路結點可能有多個鄰接結點,深度優先搜尋的政策是首先通路第一個鄰接結點,再以這個被通路的鄰接結點作為初始結點,通路它的第一鄰接結點。總結來說:每次通路目前結點後首先通路目前結點的第一個鄰接結點。

這種政策是優先縱向深度,而不是對一個結點的鄰接結點做橫向通路。算法辨別如下:

(1)通路初始結點,并标記結點v為已通路。

(2)查找結點v的第一個鄰接結點w。

(3)若w存在,則繼續執行4,否則算法結束。

(4)若w未被通路,對w進行深度優先遞歸(即把w當做另一個v,執行算法1,2,3)。

(5)查找v的w鄰接結點的下一個鄰接結點,轉到步驟3。

例如下圖,深度優先周遊的順序是1->2->4->8->5->3->6->7

圖的相關算法參考文獻

深度優先算法代碼和廣度合在一起了,都在下面

3.廣度優先周遊

廣度優先周遊類似與一個分層搜尋的過程,廣度優先周遊需要使用一個隊列以保持通路過的結點的順序,以便按照這個順序來通路這個結點的鄰接結點。算法的表述如下:

(1)通路初始結點v并标記結點v為已通路。

(2)結點v入隊列。

(3)當隊列非空時,繼續執行,否則算法結束。

(4)出隊列,取得隊頭結點u。

(5)查找結點u的第一個鄰接結點w。

(6)若結點u的鄰接結點w不存在,則轉到步驟3;否則執行下面3個步驟:

1)若結點w未被通路,則通路結點w并标記為已通路。

2)結點w入隊列。

3)查找結點u的繼w鄰接結點後的下一個鄰接結點,轉到步驟6。

例如下圖,廣度優先周遊的順序為:1->2->3->4->5->6->7->8

圖的相關算法參考文獻

深度,廣度優先算法代碼,這個代碼用的鄰接矩陣

package com.xushu.Undirectedgraph;

/**
 * Java: 鄰接表表示的"無向圖(List Undirected Graph)"
 */

import java.io.IOException;
import java.util.Scanner;

public class ListUDG {
    // 鄰接表中表對應的連結清單的頂點
    private class ENode {
        int ivex;       // 該邊所指向的頂點的位置
        ENode nextEdge; // 指向下一條弧的指針
    }

    // 鄰接表中表的頂點
    private class VNode {
        char data;          // 頂點資訊
        ENode firstEdge;    // 指向第一條依附該頂點的弧
    };

    private VNode[] mVexs;  // 頂點數組


//    /* 
//     * 建立圖(自己輸入資料)
//     */
//    public ListUDG() {
//
//        // 輸入"頂點數"和"邊數"
//        System.out.printf("input vertex number: ");
//        int vlen = readInt();
//        System.out.printf("input edge number: ");
//        int elen = readInt();
//        if ( vlen < 1 || elen < 1 || (elen > (vlen*(vlen - 1)))) {
//            System.out.printf("input error: invalid parameters!\n");
//            return ;
//        }
//        
//        // 初始化"頂點"
//        mVexs = new VNode[vlen];
//        for (int i = 0; i < mVexs.length; i++) {
//            System.out.printf("vertex(%d): ", i);
//            mVexs[i] = new VNode();
//            mVexs[i].data = readChar();
//            mVexs[i].firstEdge = null;
//        }
//
//        // 初始化"邊"
//        //mMatrix = new int[vlen][vlen];
//        for (int i = 0; i < elen; i++) {
//            // 讀取邊的起始頂點和結束頂點
//            System.out.printf("edge(%d):", i);
//            char c1 = readChar();
//            char c2 = readChar();
//            int p1 = getPosition(c1);
//            int p2 = getPosition(c2);
//            // 初始化node1
//            ENode node1 = new ENode();
//            node1.ivex = p2;
//            // 将node1連結到"p1所在連結清單的末尾"
//            if(mVexs[p1].firstEdge == null)
//              mVexs[p1].firstEdge = node1;
//            else
//                linkLast(mVexs[p1].firstEdge, node1);
//            // 初始化node2
//            ENode node2 = new ENode();
//            node2.ivex = p1;
//            // 将node2連結到"p2所在連結清單的末尾"
//            if(mVexs[p2].firstEdge == null)
//              mVexs[p2].firstEdge = node2;
//            else
//                linkLast(mVexs[p2].firstEdge, node2);
//        }
//    }

    /*
     * 建立圖(用已提供的矩陣)
     *
     * 參數說明:
     *     vexs  -- 頂點數組
     *     edges -- 邊數組
     */
    public ListUDG(char[] vexs, char[][] edges) {
        
        // 初始化"頂點數"和"邊數"
        int vlen = vexs.length;
        int elen = edges.length;

        // 初始化"頂點"
        mVexs = new VNode[vlen];
        for (int i = 0; i < mVexs.length; i++) {
            mVexs[i] = new VNode();
            mVexs[i].data = vexs[i];
            mVexs[i].firstEdge = null;
        }

        // 初始化"邊"
        for (int i = 0; i < elen; i++) {
            // 讀取邊的起始頂點和結束頂點
            char c1 = edges[i][0];
            char c2 = edges[i][1];
            // 讀取邊的起始頂點和結束頂點
            int p1 = getPosition(edges[i][0]);
            int p2 = getPosition(edges[i][1]);

            // 初始化node1
            ENode node1 = new ENode();
            node1.ivex = p2;
            // 将node1連結到"p1所在連結清單的末尾"
            if(mVexs[p1].firstEdge == null)
              mVexs[p1].firstEdge = node1;
            else
                linkLast(mVexs[p1].firstEdge, node1);
            // 初始化node2
            ENode node2 = new ENode();
            node2.ivex = p1;
            // 将node2連結到"p2所在連結清單的末尾"
            if(mVexs[p2].firstEdge == null)
              mVexs[p2].firstEdge = node2;
            else
                linkLast(mVexs[p2].firstEdge, node2);
        }
    }

    /*
     * 将node節點連結到list的最後
     */
    private void linkLast(ENode list, ENode node) {
        ENode p = list;

        while(p.nextEdge!=null)
            p = p.nextEdge;
        p.nextEdge = node;
    }

    /*
     * 傳回ch位置
     */
    private int getPosition(char ch) {
        for(int i=0; i<mVexs.length; i++)
            if(mVexs[i].data==ch)
                return i;
        return -1;
    }

    /*
     * 讀取一個輸入字元
     */
    private char readChar() {
        char ch='0';

        do {
            try {
                ch = (char)System.in.read();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } while(!((ch>='a'&&ch<='z') || (ch>='A'&&ch<='Z')));

        return ch;
    }

    /*
     * 讀取一個輸入字元
     */
    private int readInt() {
        Scanner scanner = new Scanner(System.in);
        return scanner.nextInt();
    }

    /*
     * 深度優先搜尋周遊圖的遞歸實作
     */
    private void DFS(int i, boolean[] visited) {
        
        visited[i] = true;
        System.out.printf("%c ", mVexs[i].data);
        ENode node = mVexs[i].firstEdge;
        while (node != null) {
            if (!visited[node.ivex])
                DFS(node.ivex, visited);
            node = node.nextEdge;
        }
    }

    /*
     * 深度優先搜尋周遊圖
     */
    public void DFSTravel() {
        boolean[] visited = new boolean[mVexs.length];       // 頂點通路标記

        // 初始化所有頂點都沒有被通路
        for (int i = 0; i < mVexs.length; i++)
            visited[i] = false;

        System.out.printf("DFS: ");
        for (int i = 0; i < mVexs.length; i++) {
            if (!visited[i])
                DFS(i, visited);
        }
        System.out.printf("\n");
    }

    /*
     * 廣度優先搜尋(類似于樹的層次周遊)
     */
    public void BFSTravel() {
        int head = 0;
        int rear = 0;
        int[] queue = new int[mVexs.length];            // 輔組隊列
        boolean[] visited = new boolean[mVexs.length];  // 頂點通路标記

        for (int i = 0; i < mVexs.length; i++)
            visited[i] = false;

        System.out.printf("BFS: ");
        for (int i = 0; i < mVexs.length; i++) {
            if (!visited[i]) {
                visited[i] = true;
                System.out.printf("%c ", mVexs[i].data);
                queue[rear++] = i;  // 入隊列
            }

            while (head != rear) { //當隊列不空
                int j = queue[head++];  // 出隊列
                ENode node = mVexs[j].firstEdge;
                while (node != null) {
                    int k = node.ivex;
                    if (!visited[k])
                    {
                        visited[k] = true;
                        System.out.printf("%c ", mVexs[k].data);
                        queue[rear++] = k;
                    }
                    node = node.nextEdge;
                }
            }
        }
        System.out.printf("\n");
    }

    /*
     * 列印矩陣隊列圖
     */
    public void print() {
        System.out.printf("List Graph:\n");
        for (int i = 0; i < mVexs.length; i++) {
            System.out.printf("%d(%c): ", i, mVexs[i].data);
            ENode node = mVexs[i].firstEdge;
            while (node != null) {
                System.out.printf("%d(%c) ", node.ivex, mVexs[node.ivex].data);
                node = node.nextEdge;
            }
            System.out.printf("\n");
        }
    }

    public static void main(String[] args) {
        char[] vexs = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
        char[][] edges = new char[][]{
            {'A', 'C'}, 
            {'A', 'D'}, 
            {'A', 'F'}, 
            {'B', 'C'}, 
            {'C', 'D'}, 
            {'E', 'G'}, 
            {'F', 'G'}};
        ListUDG pG;

        // 自定義"圖"(輸入矩陣隊列)
        //pG = new ListUDG();
        // 采用已有的"圖"
        pG = new ListUDG(vexs, edges);

        pG.print();   // 列印圖
        pG.DFSTravel();     // 深度優先周遊
        pG.BFSTravel();     // 廣度優先周遊
    }
}
           

參考文獻

https://www.cnblogs.com/skywang12345/category/508186.html