国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

大話數(shù)據(jù)結(jié)構(gòu)-圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷

這篇具有很好參考價值的文章主要介紹了大話數(shù)據(jù)結(jié)構(gòu)-圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

4 圖的遍歷

??圖的遍歷分為深度優(yōu)先遍歷和廣度優(yōu)先遍歷兩種。

4.1 深度優(yōu)先遍歷

??深度優(yōu)先遍歷(Depth First Search),也稱為深度優(yōu)先搜索,簡稱DFS,深度優(yōu)先遍歷,是指從某一個頂點開始,按照一定的規(guī)則,訪問并記錄下一個未訪問頂點。對于非連通圖,則是按連通分量,采用同一規(guī)則進(jìn)行深度優(yōu)先遍歷的方式,以以下圖為例:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??我們使用visited[vertexSize]來記錄已訪問的頂點,先從A開始,并把A加入到visited中,訪問規(guī)則是“下一個訪問的頂點是最右手邊的那個頂點”,注意,圖上的小人是面向我們,從上往下走的,此時visited = {A}:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??接下來,依附于頂點A的邊有(A,B)、(A,F),小人右手邊的邊是(A,B),因此延著(A,B)走,visited = {A, B}:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??依附于頂點B的邊有(B,C)、(B,I)、(B,G),小人右手邊且沒被走過的邊是(B,C),于是延著邊(B,C)走,visited = {A, B, C}:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??按照這個規(guī)則走,走到F時,visited = {A, B, C, D, E, F}:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??這時,小人的右手邊有幾條路,從右至左依次是(F,A)、(F,G)、(F、E),但頂點A在visited中,表示頂點A已經(jīng)被訪問過了,所以排除(F,A),延著(F,G)走,visited = {A, B, C, D, E, F, G}:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??這時,相對于頂點G,小人可走的路從右到左依次是(G,B)、(G,D)、(G,H),B和D已經(jīng)在visited中,因此跳過,延著(G,H)走,visited = {A, B, C, D, E, F, G, H}:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??這是,相對于頂點H,小人可走的路從右到左依次是(H,D)、(H、E),但D和E都在visited中了,這時,讓小人延原路返回,即延著(H,G)走:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??但相對于頂點G,可走的路(G,B)、(G,D)和(G,H)三條路對應(yīng)的頂點B、D、H也都在visited中了,無路可走了,繼續(xù)原路返回,到頂點F,仍然無路可走,繼續(xù)返回E,仍無路可走,繼續(xù)返回D:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??這時,發(fā)現(xiàn)了(D,I)這條路還沒走過,于是延著(D,I)走,visited = {A, B, C, D, E, F, G, H, I}:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??又無路可走了,于是原路返回,直到返回頂點A,也就是開始的那個頂點,表示圖已遍歷完。

??再來總結(jié)一下深度遍歷優(yōu)先的過程:

??(1) 先定一個規(guī)則,比如“延著依附于當(dāng)前頂點中,最左側(cè)的,未被訪問的邊進(jìn)行迭代”;

??(2) 從某一個頂點開始按定義的規(guī)則迭代;

??(3) 若有符合規(guī)則的邊,則繼續(xù)往下迭代,若無符合規(guī)則的邊,則一步一步原路返回,查找可迭代的邊;

??(4) 當(dāng)原路返回到最開始的那個頂點時,迭代完畢;

??實際上整體上是一個遞歸調(diào)度的過程,主要就是找到“下一條邊”。

??注意,深度優(yōu)先遍歷的規(guī)則并不是固定不變的,只要最終結(jié)果遵循“按一定規(guī)則,逐步訪問結(jié)點的下一個鄰邊”即可。

4.1.1 鄰接矩陣的深度優(yōu)先遍歷

??我們舉幾個例子:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??對這些圖使用深度優(yōu)先遍歷時,找“下一條未被訪問邊”的方式是:

??(1) 從第一個頂點開始,訪問arc[0][1]、arc[0][2]…arc[0][n],找到第一個未被訪問的邊,邊的判斷是,如果為圖,則值為1表示存在邊,如果為網(wǎng),則值不為無窮大且arc[i][j]中i不等于j表示存在邊;

??(2) 找到這個邊后,訪問它,假設(shè)這個邊為arc[0][x];

??(3) 然后繼續(xù)訪問arc[x],找到x的未被訪問的邊,即遞歸第(1)、(2)步,直到所有關(guān)聯(lián)的邊都訪問完;

??(4) 若此時,結(jié)點還未迭代完,則從第二個“未被訪問的頂點”開始,繼續(xù)迭代;

??因此如上無向圖的遍歷過程如下所示:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??過程為:

??(0) iterate C;

??(1) 遍歷arc[0][j],尋找C相關(guān)的頂點,找到(C,D),visit C,visit D;

??(2) 遍歷arc[1][j],尋找D相關(guān)的頂點,找到(D,C),兩個頂點都被訪問過,跳過;

??(3) 找到(D,A),visit A;

??(4) 遍歷arc[2][j],尋找A相關(guān)的頂點,找到(A,C),兩個頂點都被訪問過,跳過;

??(5) 找到(A,D),兩個頂點都被訪問過,跳過;

??(6) 找到(A,B),visit B;

??(7) 遍歷arc[3][j],尋找B相關(guān)的頂點,找到(B,C),兩個頂點都被訪問過,跳過;

??(8) 找到(B,D),值為0,不相關(guān),跳過;

??(9) 找到(B,A),兩個頂點都被訪問過,跳過;

??(10) 找到(B,F),visit F;

??(11) 遍歷arc[4][j],尋找F相關(guān)的頂點,找到(F,C),值為0,不相關(guān),跳過;

??(12) 找到(F,D),值為0,不相關(guān),跳過;

??(13) 找到(F,A),值為0,不相關(guān),跳過;

??(14) 找到(F,B),兩個頂點都被訪問過,跳過;

??(15) 找到(F,E),visit E,此時所有頂點均訪問完畢,結(jié)束;

??如上有向網(wǎng)的遍歷過程如下所示:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??過程為:

??(0) iterate E;

??(1) 迭代arc[0][j],尋找E指向的頂點,找到<E,F>,visit E,然后發(fā)現(xiàn)數(shù)組值為無窮大,不相關(guān),跳過;

??(2) 找到<E,C>,值為無窮大,不相關(guān),跳過;

??(3) 找到<E,A>,visit A;

??(4) 迭代arc[3][j],尋找A指向的頂點,找到<A,E>,值為無窮大,不相關(guān),跳過;

??(5) 找到<A,F>,值為無窮大,不相關(guān),跳過;

??(6) 找到<A,C>,值為無窮大,不相關(guān),跳過;

??(7) 找到<A,B>,值為無窮大,不相關(guān),跳過;

??(8) 找到<A,D>,visit D;

??(9) 迭代arc[5][j],尋找D指向的頂點,找到<D,E>,值為無窮大,不相關(guān),跳過;

??(10) 找到<D,F>,visit F;

??(11) 迭代arc[1][j],尋找F指向的頂點,找到<F,E>,值為無窮大,不相關(guān),跳過;

??(12) 找到<F,C>,值為無窮大,不相關(guān),跳過;

??(13) 找到<F,A>,值為無窮大,不相關(guān),跳過;

??(14) 找到<F,B>,值為無窮大,不相關(guān),跳過;

??(15) 找到<F,D>,值為無窮大,不相關(guān),跳過;

??(16) F處理完畢,沒有相關(guān)的頂點,于是回退一步,到D,繼續(xù)迭代arc[5][j],找到<D,C>,visit C;

??(17) 迭代arc[2][j],尋找C指向的頂點,找到<C,E>,E已被訪問,跳過;

??(18) 找到<C,F>,值為無窮大,不相關(guān),跳過;

??(19) 找到<C,A>,值為無窮大,不相關(guān),跳過;

??(20) 找到<C,B>,visit B,此時所有頂點均訪問完畢,結(jié)束;

??代碼實現(xiàn)如下所示:

/**
 * 對圖進(jìn)行深度優(yōu)先遍歷
 *
 * @author Korbin
 * @date 2023-02-02 17:02:23
 **/
public List<T> deepFirstTraverse() {

    List<T> visitedVertex = new ArrayList<>();
    boolean[] visited = new boolean[vertexNum];

    for (int i = 0; i < vertexNum && visitedVertex.size() < vertexNum; i++) {
        deepFirstTraverse(visitedVertex, visited, i);
    }

    return visitedVertex;

}

/**
 * 對圖進(jìn)行深度迭代
 *
 * @param visitedVertex 迭代結(jié)果
 * @param visited       已訪問過的頂點
 * @param index         接著要迭代的結(jié)點
 * @author Korbin
 * @date 2023-02-02 17:26:43
 **/
public void deepFirstTraverse(List<T> visitedVertex, boolean[] visited, int index) {

    // 取出當(dāng)前頂點
    if (!visited[index]) {
        // 當(dāng)前頂點未被訪問,才繼續(xù)
        T ver = vertex[index];
        visitedVertex.add(ver);
        visited[index] = true;
        // 取出當(dāng)前頂點可走的邊
        for (int j = 0; j < arc[index].length && visitedVertex.size() < vertexNum; j++) {

            if (j != index) {
                switch (type) {
                    case UNDIRECTED:
                    case DIRECTED: {
                        // 無向圖或有向圖,為1且頂點未被訪問表示可以走
                        try {
                            int weight = (int) (arc[index][j]);
                            if (weight == 1 && !visited[j]) {
                                // 可以繼續(xù)往下走
                                deepFirstTraverse(visitedVertex, visited, j);
                            }
                        } catch (NumberFormatException e) {
                            // do nothing
                        }
                        break;
                    }
                    case UNDIRECTED_NETWORK:
                    case DIRECTED_NETWORK: {
                        // 無向圖或有向網(wǎng)
                        // 不為infinity,且頂點未被訪問
                        if (!arc[index][j].equals(infinity) && !visited[j]) {
                            // 可以繼續(xù)往下走
                            deepFirstTraverse(visitedVertex, visited, j);
                        }
                        break;
                    }
                }
            }

        }
    }
}

4.1.2 鄰接表的深度優(yōu)先遍歷

??考慮如下有向圖:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??從第一個頂點開始,打到它未被訪問的下一個頂點,尋找的過程是先找firstEdge,如果firstEdge指向的頂點已被訪問,則找firstEdge的next,直到找到這個頂點為止;接著訪問這個頂點的指向下一個未訪問的頂點,尋找方式與第一個頂點相同。

??該鄰接表的遍歷過程如下所示:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??整體過程為:

??(0) iterate C, visit C;

??(1) 找頂點C相關(guān)的頂點,找到(C,D),visit D;

??(2) 找頂點D相關(guān)的頂點,找到(D,C),兩個頂點都被訪問過,跳過;

??(3) 繼續(xù)找頂點D相關(guān)的頂點,找到(D,A),visit A;

??(4) 找頂點A相關(guān)的頂點,找到(A,C),兩個頂點都被訪問過,跳過;

??(5) 繼續(xù)找頂點A相關(guān)的頂點,找到(A,D),兩個頂點都被訪問過,跳過;

??(6) 繼續(xù)找頂點A相關(guān)的頂點,找到(A,B),visit B;

??(7) 找頂點B相關(guān)的頂點,找到(B,C),兩個頂點都被訪問過,跳過;

??(8) 繼續(xù)找頂點B相關(guān)的頂點,找到(B,A),兩個頂點都被訪問過,跳過;

??(9) 繼續(xù)找頂點B相關(guān)的頂點,找到(B,F),visit F;

??(10) 找頂點F相關(guān)的頂點,找到(F,B),兩個頂點都被訪問過,跳過;

??(11) 繼續(xù)找頂點F相關(guān)的頂點,找到(F,E),visit E,此時所有頂點都訪問完畢,結(jié)束;

??相應(yīng)地,有向圖的鄰接表遍歷過程如下所示:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??即:

??(0) iterate C,visit C;

??(1) 找頂點C指向的頂點,找到<C,B>,visit B;

??(2) 找頂點B指向的頂點,找到<B,A>,visit A;

??(3) 找頂點A指向的頂點,找到<A,D>,visit D;

??(4) 找頂點D指向的頂點,找到<D,C>,兩個頂點都被訪問過,跳過;

??(5) 繼續(xù)找頂點D指向的頂點,找到<D,B>,兩個頂點都被訪問過,跳過;

??(6) 繼續(xù)找頂點D指向的頂點,找到<D,F>,visit F;F沒有指向的頂點,回退到D;繼續(xù)找頂點D指向的頂點,D所有指向的頂點都已訪問,回退到B;繼續(xù)找頂點B指向的頂點,B所有指向的頂點都已被訪問,回退到C;

??(7) 繼續(xù)找頂點C指向的頂點,找到<C,E>,visit E,此時所有頂點訪問完畢,結(jié)束;

??除了鄰接表外,還有一種逆鄰接表,逆鄰接表使用的遍歷方法與鄰接表不同,因為邊集數(shù)組中保存的是每個頂點被指向的信息,如下:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??逆鄰接表的查找下一個未訪問頂點的過程,是“遍歷邊集數(shù)組,找到firstEdge或nextEdge的為當(dāng)前頂點的邊集數(shù)組結(jié)點,這個邊集數(shù)組元素關(guān)聯(lián)的第一個未被訪問的頂點數(shù)組元素,就是要找的下一個頂點”,如上逆鄰接表的遍歷過程如下:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??(1) 從第一個頂點C開始迭代,將它加入訪問列表,visit C;

??(2) 迭代所有邊集數(shù)組,找到C指向的頂點,因為C已被訪問,因此忽略它,先看D,只有邊<A,D>,與頂點C不相關(guān),跳過;

??(3) 看頂點A,第一條邊<B,A>,與頂點C不相關(guān),跳過;

??(4) 繼續(xù)看頂點A,第二條邊<E,A>,與頂點C不相關(guān),跳過;

??(5) A的邊看完了,看B的邊,第一條邊<C,B>,找到頂點B是C指向的頂點,且由于是按下標(biāo)從小到大迭代的,因此它一定是C指向的,且下標(biāo)最小的頂點,因此,visit B;

??(6) 接下來看頂點B指向的頂點,首先是頂點C,因為已訪問過,因此忽略,然后是頂點D,有邊<A,D>,與頂點B不相關(guān),跳過;

??(7) 然后看頂點A,有邊<B,A>,A是頂點B指向的頂點,因此visit A;

??(8) 接下來看頂點A指點的頂點,頂點C已被訪問,仍然跳過,然后是頂點D,打到邊<A,D>,符合要求,因此,visit D;

??(9) 接下來看頂點D指向的頂點,前面的幾個頂點C、D、A、B都已被訪問過,跳過,看頂點F,有邊<D,F>,符合要求,因此,visit F;

??(10) 接下來看頂點F指向的頂點,前面的幾個頂點C、D、A、B、F都已被訪問,跳過,看頂點E,有邊<C,E>,與頂點F不相關(guān),跳過;

??(11) 這時,所有頂點都迭代完畢,但仍未訪問到所有頂點,因此回到第(1)步,繼續(xù)迭代頂點,C已迭代過,于是看頂點D,頂點D已被訪問,跳過;

??(12) 繼續(xù),迭代頂點A,已被訪問,跳過;

??(13) 繼續(xù),迭代頂點B,已被訪問,跳過;

??(14) 繼續(xù),迭代頂點F,已被訪問,跳過;

??(15) 繼續(xù),迭代頂點E,未被訪問,因此,visit E,此時,所有頂點都訪問完畢,遍歷結(jié)束;

??代碼實現(xiàn)如下所示:

/**
 * 對圖進(jìn)行深度優(yōu)先遍歷
 *
 * @author Korbin
 * @date 2023-02-02 19:59:26
 **/
public List<T> deepFirstTraverse() {
    List<T> vertexList = new ArrayList<>();
    boolean[] visited = new boolean[vertexNum];

    // 對于鄰接表,從第一個頂點開始處理,先處理firstEdge
    for (int i = 0; i < vertexNum && vertexList.size() < vertexNum; i++) {
        if (!visited[i]) {

            System.out.println("iterate " + vertexes[i].getVertex());

            VertexNode<T, W> vertexNode = vertexes[i];
            vertexList.add(vertexNode.getVertex());
            visited[i] = true;

            if (reverseAdjacency) {
                deepFirstTraverse(vertexList, visited, i);
            } else {
                deepFirstTraverse(vertexList, visited, vertexNode);
            }

        }

    }

    return vertexList;
}

/**
 * 對使用逆鄰接表存儲的圖進(jìn)行深度優(yōu)先遍歷
 *
 * @param vertexList 遍歷結(jié)果
 * @param visited    訪問列表
 * @param index      當(dāng)前遍歷的下標(biāo)
 * @author Korbin
 * @date 2023-02-06 18:13:34
 **/
public void deepFirstTraverse(List<T> vertexList, boolean[] visited, int index) {

    int minRefIndex = -1;

    // 找到index指向的下標(biāo)最小的未訪問的頂點
    boolean got = false;
    for (int i = 0; i < vertexNum && vertexList.size() < vertexNum && !got; i++) {
        if (!visited[i]) {
            VertexNode<T, W> vertexNode = vertexes[i];

            EdgeNode<W> edgeNode = vertexNode.getFirstEdge();
            while (null != edgeNode && vertexList.size() < vertexNum) {
                int edgeIndex = edgeNode.getIndex();

                System.out.format("check %s-%s\r\n", vertexes[edgeIndex].getVertex(), vertexes[i].getVertex());

                if (edgeIndex == index) {
                    minRefIndex = i;
                    got = true;
                    break;
                }
                edgeNode = edgeNode.getNext();
            }
        }
    }

    if (minRefIndex != -1) {
        if (!visited[minRefIndex]) {
            // 訪問這個頂點
            visited[minRefIndex] = true;
            vertexList.add(vertexes[minRefIndex].getVertex());

            System.out.println("in " + vertexes[minRefIndex].getVertex());

            // 再訪問這個頂點指向的頂點
            deepFirstTraverse(vertexList, visited, minRefIndex);
        }
    }
}

/**
 * 對使用鄰接表存儲的圖進(jìn)行深度優(yōu)先遍歷
 *
 * @param vertexList 遍歷結(jié)果
 * @param visited    已訪問的頂點
 * @param vertexNode 正在訪問的頂點
 * @author Korbin
 * @date 2023-02-03 20:26:22
 **/
public void deepFirstTraverse(List<T> vertexList, boolean[] visited, VertexNode<T, W> vertexNode) {
    EdgeNode<W> firstEdge = vertexNode.getFirstEdge();
    while (null != firstEdge && vertexList.size() < vertexNum) {

        System.out.format("check %s-%s\r\n", vertexNode.getVertex(), vertexes[firstEdge.getIndex()].getVertex());

        int index = firstEdge.getIndex();
        if (!visited[index]) {
            // 把它加入到遍歷結(jié)果中,然后遞歸處理它對應(yīng)的頂點
            VertexNode<T, W> nextNode = vertexes[index];
            vertexList.add(nextNode.getVertex());
            visited[index] = true;

            deepFirstTraverse(vertexList, visited, nextNode);
        }
        // 取下一個edge
        firstEdge = firstEdge.getNext();

    }
}

4.1.3 十字鏈表的深度優(yōu)先遍歷

??十字鏈表是在鄰接表上的進(jìn)一步優(yōu)化,因此十字鏈表的深度優(yōu)先遍歷方式與鄰接表類似,鄰接表是處理firstEdge,十字鏈表處理的是firstOut和nextHead,因為firstOut就等于鄰接表(非逆鄰接表)的firstEdge,而nextHead相關(guān)于鄰接表的EdgeNode中的next,大致邏輯為:

??(1) 從第一個頂點開始處理,按如下規(guī)則:

????1) 如果頂點X未被訪問,則訪問它;

????2) 找到頂點X的指向的下一個未被訪問的頂點,我們知道,首先是firstOut,然后是firstOut之后弧結(jié)點的nextHead;

????3) 找到這個頂點后,訪問它,然后遞歸1)、2)步;

??(2) 繼續(xù)迭代頂點列表中的其他頂點,若還有未訪問的頂點,則按(1)的規(guī)則處理,直到所有頂點處理完畢;

??以下面的十字鏈表為例:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??下圖展示了它的深度優(yōu)先遍歷過程:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??(0) 先忽略所有firstIn相關(guān)的線,然后iterate E,visit E;

??(1) 找到E指向的頂點,找到<E,A>,visit A;

??(2) 找到A指向的頂點,找到<A,D>,visit D;

??(3) 找到D指向的頂點,找到<D,F>,visit F;F沒有指向的頂點,因此回退到D;

??(4) 找到D指向的頂點,找到<D,C>,visit C;

??(5) 找到C指向的頂點,找到<C,E>,兩個頂點都已被訪問,跳過;

??(6) 繼續(xù)找到C指向的頂點<C,B>,visit B,此時所有頂點都已被訪問,結(jié)束;

??代碼如下所示:

/**
 * 對圖進(jìn)行深度優(yōu)先遍歷
 *
 * @author Korbin
 * @date 2023-02-02 19:59:26
 **/
public List<T> deepFirstTraverse() {
    List<T> vertexList = new ArrayList<>();
    boolean[] visited = new boolean[vertexNum];

    // 對于鄰接表,從第一個頂點開始處理,先處理firstEdge
    for (int i = 0; i < vertexNum && vertexList.size() < vertexNum; i++) {
        if (!visited[i]) {
            AcrossLinkVertexNode<T, W> vertexNode = vertexes[i];
            vertexList.add(vertexNode.getVertex());
            visited[i] = true;

            deepFirstTraverse(vertexList, visited, vertexNode);

        }

    }
    return vertexList;
}

/**
 * 對圖進(jìn)行深度優(yōu)先遍歷
 *
 * @param vertexList 遍歷結(jié)果
 * @param visited    已訪問于列表
 * @param vertexNode 待處理的頂點
 * @author Korbin
 * @date 2023-02-03 19:33:32
 **/
private void deepFirstTraverse(List<T> vertexList, boolean[] visited, AcrossLinkVertexNode<T, W> vertexNode) {

    AcrossLinkEdgeNode<W> firstEdge = vertexNode.getFirstOut();
    int nextIndex = -1;
    while (null != firstEdge && vertexList.size() < vertexNum) {
        // 指向的頂點下標(biāo)為headIndex
        int index = firstEdge.getHeadIndex();

        if (!visited[index]) {
            vertexList.add(vertexes[index].getVertex());
            visited[index] = true;
            nextIndex = index;

            // 遞歸處理下一個頂點的鄰邊
            deepFirstTraverse(vertexList, visited, vertexes[nextIndex]);
        }
        firstEdge = firstEdge.getNextHead();
    }
}

4.1.4 鄰接多重表的深度優(yōu)先遍歷

??考慮如下鄰接多重表:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??第一個頂點是C,它有三條關(guān)聯(lián)的邊,分別是(C,A)、(C,B)和(C,D),我們把規(guī)則定為,下一個未訪問的鄰邊是在頂點數(shù)組中下標(biāo)最小,且未訪問的那條邊,這個定義與鄰接多重表的存儲結(jié)構(gòu)相同,鄰接多重表的存儲設(shè)計是“firstEdge指向第一條邊,iLink指向下一條邊(下一條邊的jVex必須為當(dāng)前頂點),下一條邊的jLink指向下下一條邊(并不要求jVex為當(dāng)前頂點),下下一條邊的jLink指向下下一條邊(并不要求jVex為當(dāng)前頂點),依此類推”,因此鄰接多重表深度優(yōu)先遍歷的過程是:

??(1) 從第一個頂點X開始,找到這個頂點下一條未被訪問的邊(X,Y):

????1) 若能找到Y(jié),則訪問Y,并查找Y的下一條未被訪問的邊;

????2) 若Y不存在,則原路返回,走上一個頂點的未被訪問的邊;

??(2) 遞歸執(zhí)行第(1)步,直到找不到下一條未被訪問的邊時,繼續(xù)對第二個頂點進(jìn)行處理,直到所有頂點處理完畢。

??如下為該鄰接多重表的深度優(yōu)先遍歷過程:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??過程為:

??(0) iterate C,visit C;

??(1) 找C關(guān)聯(lián)的頂點,找到(C,D),visit D;

??(2) 找D關(guān)聯(lián)的頂點,找到(D,A),visit A;

??(3) 找A關(guān)聯(lián)的頂點,找到(A,C),兩個頂點都已訪問,跳過;

??(4) 繼續(xù)找A關(guān)聯(lián)的頂點,找到(D,A),兩個頂點都已訪問,跳過;

??(5) 繼續(xù)找A關(guān)聯(lián)的頂點,找到(A,B),visit B;

??(6) 找B關(guān)聯(lián)的頂點,找到(B,C),兩個頂點都已訪問,跳過;

??(7) 繼續(xù)找B關(guān)聯(lián)的頂點,找到(A,B),兩個頂點都已訪問,跳過;

??(8) 繼續(xù)找B關(guān)聯(lián)的頂點,找到(F,B),visit F;

??(9) 找F關(guān)聯(lián)的頂點,找到(F,B),兩個頂點都已訪問,跳過;

??(10) 繼續(xù)找F關(guān)聯(lián)的頂點,找到(E,F),visit E,所有頂點都已訪問,結(jié)束;

??實現(xiàn)代碼如下所示:

/**
 * 對圖進(jìn)行深度優(yōu)先遍歷
 *
 * @return 遍歷結(jié)果
 * @author Korbin
 * @date 2023-02-03 17:09:46
 **/
public List<T> deepFirstTraverse() {

    List<T> vertexList = new ArrayList<>();
    boolean[] visited = new boolean[vertexNum];

    for (int i = 0; i < vertexNum && vertexList.size() < vertexNum; i++) {
        // 從第1個頂點開始找
        if (!visited[i]) {

            AdjacencyMultiVertexNode<T, W> vertexNode = vertexes[i];
            vertexList.add(vertexNode.getVertex());
            visited[i] = true;

            deepFirstTraverse(vertexList, visited, vertexNode);
        }

    }

    return vertexList;

}

/**
 * 對圖進(jìn)行深度優(yōu)先遍歷
 *
 * @param vertexList 遍歷結(jié)果
 * @param visited    頂點是否已被訪問
 * @param vertexNode 待迭代的頂點
 * @author Korbin
 * @date 2023-02-03 17:44:43
 **/
public void deepFirstTraverse(List<T> vertexList, boolean[] visited, AdjacencyMultiVertexNode<T, W> vertexNode) {
    AdjacencyMultiEdgeNode<W> firstEdge = vertexNode.getFirstEdge();
    if (null != firstEdge) {
        // firstEdge的關(guān)聯(lián)頂點下標(biāo)是jVex
        int index = firstEdge.getJVex();
        int myIndex = firstEdge.getIVex();

        if (!visited[index]) {
            // 未訪問
            AdjacencyMultiVertexNode<T, W> nextVertexNode = vertexes[index];
            vertexList.add(nextVertexNode.getVertex());
            visited[index] = true;

            // 然后處理index對應(yīng)的頂點,找它的下一個未訪問的鄰邊
            deepFirstTraverse(vertexList, visited, nextVertexNode);
        } else {
            // 已訪問
            // 下一個相關(guān)邊是firstEdge的iLink
            AdjacencyMultiEdgeNode<W> nextEdge = firstEdge.getILink();
            if (null != nextEdge) {
                // 這個相關(guān)邊的關(guān)聯(lián)頂點是iVex
                index = nextEdge.getIVex();

                if (!visited[index]) {
                    // 未訪問
                    AdjacencyMultiVertexNode<T, W> nextVertexNode = vertexes[index];
                    vertexList.add(nextVertexNode.getVertex());
                    visited[index] = true;

                    // 然后處理index對應(yīng)的頂點,找它的下一個未訪問的鄰邊
                    deepFirstTraverse(vertexList, visited, nextVertexNode);
                } else {
                    // 已訪問
                    // 下一條,以及下下條等,相關(guān)邊都是jLink
                    nextEdge = nextEdge.getJLink();
                    while (null != nextEdge && vertexList.size() < vertexNum) {
                        // 關(guān)聯(lián)頂點可能是iVex,也可能是jVex
                        int iVex = nextEdge.getIVex();
                        int jVex = nextEdge.getJVex();
                        if (iVex == myIndex) {
                            // 關(guān)聯(lián)頂點是JVex
                            if (!visited[jVex]) {
                                AdjacencyMultiVertexNode<T, W> nextVertexNode = vertexes[jVex];
                                vertexList.add(nextVertexNode.getVertex());
                                visited[jVex] = true;

                                // 然后處理index對應(yīng)的頂點,找它的下一個未訪問的鄰邊
                                deepFirstTraverse(vertexList, visited, nextVertexNode);
                            } else {
                                nextEdge = nextEdge.getJLink();
                            }
                        } else if (jVex == myIndex) {
                            // 關(guān)聯(lián)頂點是IVex
                            if (!visited[iVex]) {
                                AdjacencyMultiVertexNode<T, W> nextVertexNode = vertexes[iVex];
                                vertexList.add(nextVertexNode.getVertex());
                                visited[iVex] = true;

                                // 然后處理index對應(yīng)的頂點,找它的下一個未訪問的鄰邊
                                deepFirstTraverse(vertexList, visited, nextVertexNode);
                            } else {
                                nextEdge = nextEdge.getILink();
                            }
                        }
                    }
                }
            }
        }
    }

}

4.1.5 邊集數(shù)組的深度優(yōu)先遍歷

??邊集數(shù)組存儲了每條邊的begin、end信息,由于無向圖/網(wǎng)和有向圖/網(wǎng)不同,無向圖/網(wǎng)的begin和end可以是邊上的任何一個頂點,因此對于無向圖/網(wǎng)和有向圖/網(wǎng)的遍歷方式不同,但整體方向差不多:從下標(biāo)最小的那個頂點開始,找每個頂點關(guān)聯(lián)的、未被訪問的、下標(biāo)最小的那個頂點進(jìn)行訪問。

??先看無向圖/網(wǎng):

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??從下標(biāo)最小的那個頂點開始找,即從頂點C開始找,找它的邊,有(B,C)、(C,A)和(C,D),下標(biāo)最小的關(guān)聯(lián)頂點是D,然后找D的邊,有(A,D)、(C,D),C被訪問過了,因此下一個頂點是C,依此類推,整體過程如下:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??整體過程是:

??(0) iterate C;

??(1) 找到C關(guān)聯(lián)的頂點,找到(C,D),visit C,visit D;

??(2) 找到D關(guān)聯(lián)的頂點,找到(A,D),visit A;

??(3) 找到A關(guān)聯(lián)的頂點,找到(A,B),visit B;

??(4) 找到B關(guān)聯(lián)的頂點,找到(B,F),visit F;

??(5) 找到F關(guān)聯(lián)的頂點,找到(F,E),visit E,所有頂點訪問完畢,結(jié)束;

??無向圖/網(wǎng)在找“下一個頂點”時,找到的邊中,可以begin等于當(dāng)前頂點,也可以end等于當(dāng)前頂點,但有向網(wǎng)則不同,只能找end為當(dāng)前頂點的邊,看如下有向圖:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??處理過程如下:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??整體過程是:

??(0) iterate E;

??(1) 找E指向的頂點,找到<E,A>,visit E,visit A;

??(2) 找A指向的頂點,找到<A,D>,visit D;

??(3) 找D指向的頂點,找到<D,F>,visit F;F沒有指向任何頂點,回退到D;

??(4) 找D指向的頂點,找到<D,C>,visit C;

??(5) 找C指向的頂點,找到<C,B>,visit B,此時,所有頂點訪問完畢,結(jié)束;

??代碼實現(xiàn)如下所示:

/**
 * 對圖進(jìn)行深度優(yōu)先遍歷
 *
 * @return 遍歷結(jié)果
 * @author Korbin
 * @date 2023-02-06 14:25:42
 **/
public List<T> deepFirstTraverse() {
    List<T> vertexList = new ArrayList<>();
    boolean[] visited = new boolean[vertexNum];
    for (int i = 0; i < vertexNum && vertexList.size() < vertexNum; i++) {
        deepFirstTraverse(vertexList, visited, i);
    }
    return vertexList;
}

/**
 * 對圖進(jìn)行深度優(yōu)先遍歷
 *
 * @param vertexList 遍歷結(jié)果
 * @param visited    訪問記錄
 * @param index      待處理的下標(biāo)
 * @author Korbin
 * @date 2023-02-06 14:25:58
 **/
public void deepFirstTraverse(List<T> vertexList, boolean[] visited, int index) {

    // 找下標(biāo)為i的頂點關(guān)聯(lián)的邊中,關(guān)聯(lián)頂點下標(biāo)最小且未訪問的頂點
    int minReleVertex = -1;
    for (int j = 0; j < arc.length && vertexList.size() < vertexNum; j++) {
        EdgeListEdgeNode<W> edgeNode = arc[j];
        int begin = edgeNode.getBegin();
        int end = edgeNode.getEnd();

        switch (type) {
            case UNDIRECTED:
            case UNDIRECTED_NETWORK: {
                if (begin == index && !visited[end]) {
                    if (minReleVertex == -1 || minReleVertex > end) {
                        minReleVertex = end;
                    }
                } else if (end == index && !visited[begin]) {
                    if (minReleVertex == -1 || minReleVertex > begin) {
                        minReleVertex = begin;
                    }
                }
                break;
            }
            case DIRECTED:
            case DIRECTED_NETWORK: {
                if (begin == index && !visited[end]) {
                    if (minReleVertex == -1 || minReleVertex > end) {
                        minReleVertex = end;
                    }
                }
                break;
            }
        }

    }

    if (!visited[index]) {
        // 訪問該頂點
        visited[index] = true;
        vertexList.add(vertex[index]);
    }

    if (minReleVertex != -1 && !visited[minReleVertex]) {
        // 訪問該頂點的下標(biāo)最小的關(guān)聯(lián)頂點
        visited[minReleVertex] = true;
        vertexList.add(vertex[minReleVertex]);

        // 接下來,訪問關(guān)聯(lián)頂點的“下標(biāo)最小的關(guān)聯(lián)頂點”
        deepFirstTraverse(vertexList, visited, minReleVertex);
		
		// 處理完畢后,應(yīng)繼續(xù)處理本頂點,即“下一個頂點沒有關(guān)聯(lián)的頂點,因此回退一步”
		deepFirstTraverse(vertexList, visited, index);
    }

}

4.2 廣度優(yōu)先遍歷

??廣度優(yōu)先遍歷(Breadth First Search),又稱為廣度優(yōu)先搜索,簡稱BFS,廣度優(yōu)先遍歷有點類似于樹的層序遍歷。

4.2.1 鄰接矩陣的廣度優(yōu)先遍歷

??考慮如下無向圖:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??廣度優(yōu)先遍歷的方法是:從下標(biāo)最小的頂點C開始,訪問C,然后找到它的下一層,訪問它的下一層,然后找到下一層的下一層,訪問它們,依此類推。

??在無向圖中我們這邊實現(xiàn):

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??(0) 我們先建一個隊列用于輔助;

??(1) 從頂點C開始,把它的下標(biāo)加入隊列,此時隊列里面只有C;

??(2) 從隊列中取出隊頭的數(shù)據(jù),即C的下標(biāo)0,訪問C,然后迭代arc[0][j],weight為1的依次加入隊列,此時隊列從尾到頭依次是B、A、D,已訪問列表里有{C};

??(3) 從隊列中取出隊頭的數(shù)據(jù),即D的下標(biāo)1,訪問D,然后迭代arc[1][j],weight為1且未被訪問的依次加入隊列,此時隊列從尾到頭依次是A、B、A,已訪問列表里有{C, D};

??(4) 從隊列中取出隊頭的數(shù)據(jù),即A的下標(biāo)2,訪問A,然后迭代arc[2][j],weight為1且未被訪問的依次加入隊列,此時隊列從尾到頭依次是B、A、B,已訪問列表里有{C, D, A};

??(5) 從隊列中取出隊頭的數(shù)據(jù),即B的下標(biāo)3,訪問B,然后迭代arc[3][j],weight為1且未被訪問的依次加入隊列,此時隊列從尾到頭依次是F、B、A,已訪問列表里有{C, D, A, B};

??(6) 從隊列中取出隊頭的數(shù)據(jù),即A的下標(biāo)2,發(fā)現(xiàn)A已被訪問,跳過,此時隊列從尾到頭依次是F、B,已訪問列表里有{C, D, A, B};

??(7) 從隊列中取出隊頭的數(shù)據(jù),即B的下標(biāo)3,發(fā)現(xiàn)B已被訪問,跳過,此時隊列從尾到頭依次是F,已訪問列表里有{C, D, A, B};

??(8) 從隊列中取出隊頭的數(shù)據(jù),即F的下標(biāo)4,訪問F,然后迭代arc[4][j],weight為1且未被訪問的依次加入隊列,此時隊列從尾到頭依次是E,已訪問列表里有{C, D, A, B, F};

??(9) 從隊列中取出隊頭的數(shù)據(jù),即E的下標(biāo)5,訪問E,這時發(fā)現(xiàn)所有頂點均已訪問完畢,結(jié)束遍歷,得到結(jié)果{C, D, A, B, F, E};

??有向圖/網(wǎng)的實現(xiàn)類似,考慮如下有向網(wǎng):

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??遍歷過程如下所示:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??(1) 仍然使用一個輔助隊列,用于存儲頂點下標(biāo),從下標(biāo)為0的頂點開始迭代,先將它入隊,此時隊列里面只有E;

??(2) 從隊列中取出隊頭數(shù)據(jù),即E的下標(biāo)0,訪問它,迭代arc[0][j],取出相關(guān)邊,有<E,A>,將A插入隊列,此時隊列里面只有A,已訪問頂點列表為{E};

??(3) 從隊列中取出隊頭數(shù)據(jù),即A的下標(biāo)3,訪問它,迭代arc[3][j],取出相關(guān)邊,有<A,D>,將D插入隊列,此時隊列里面只有D,已訪問頂點列表為{E, A};

??(4) 從隊列中取出隊頭數(shù)據(jù),即D的下標(biāo)5,訪問它,迭代arc[5][j],取出相關(guān)邊,有<D,F>、<D,C>、<D,B>,將F、C、B依次插入隊列,此時隊列從隊尾到隊頭依次是B、C、F,已訪問頂點列表為{E, A, D};

??(5) 從隊列中取出隊頭數(shù)據(jù),即F的下標(biāo)1,訪問它,迭代arc[1][j],取出相關(guān)邊,沒有,不進(jìn)行處理,此時隊列從隊尾到隊頭依次是B、C,已訪問頂點列表為{E, A, D, F};

??(6) 從隊列中取出隊頭數(shù)據(jù),即C的下標(biāo)2,訪問它,迭代arc[2][j],取出相關(guān)邊,有<C,E>、<C,B>,因為頂點E已被訪問,因此忽略它,把B加入到隊列,此時隊列從隊尾到隊頭依次是B、B,已訪問頂點列表為{E, A, D, F, C};

??(7) 從隊列中取出隊頭數(shù)據(jù),即B的下標(biāo)4,訪問它,發(fā)現(xiàn)所有頂點已訪問完畢,遍歷結(jié)束,得到結(jié)果{E, A, D, F, C, B};

??代碼實現(xiàn)如下所示:

/**
 * 對圖進(jìn)行廣度優(yōu)先遍歷
 *
 * @return 遍歷結(jié)果
 * @author Korbin
 * @date 2023-02-06 19:33:16
 **/
public List<T> breadthFirstTraverse() {

    List<T> vertexList = new ArrayList<>();
    boolean[] visited = new boolean[vertexNum];

    LinkQueue<Integer> queue = new LinkQueue<>();
    queue.init();

    for (int i = 0; i < vertexNum && vertexList.size() < vertexNum; i++) {

        if (!visited[i]) {
            // 入隊列
            LinkListNode<Integer> node = new LinkListNode<>();
            node.setData(i);
            queue.insert(node);

            System.out.println("iterate " + vertex[i]);

            while (!queue.isEmpty() && vertexList.size() < vertexNum) {
                // 一個個取出來訪問,并把它們的下一層放入隊列
                node = queue.delete();
                int index = node.getData();

                if (!visited[index]) {

                    vertexList.add(vertex[index]);
                    visited[index] = true;
                    System.out.println("in " + vertex[index]);

                    for (int j = 0; j < vertexNum && vertexList.size() < vertexNum; j++) {
                        if (j != index && !visited[j]) {

                            boolean canInsert = false;

                            switch (type) {
                                case UNDIRECTED:
                                case DIRECTED: {
                                    // 無向圖和有向圖,weight為1表示頂點相關(guān)
                                    try {
                                        int weight = (int) arc[index][j];
                                        if (weight == 1) {
                                            canInsert = true;
                                        }
                                    } catch (NumberFormatException e) {
                                        // do nothing
                                    }

                                    break;
                                }
                                case UNDIRECTED_NETWORK:
                                case DIRECTED_NETWORK: {
                                    // 無向網(wǎng)和有向網(wǎng),weight不為infinity表示頂點相關(guān)
                                    if (!arc[index][j].equals(infinity)) {
                                        canInsert = true;
                                    }
                                }
                            }

                            if (canInsert) {
                                // 把下一層入隊
                                node = new LinkListNode<>();
                                node.setData(j);
                                queue.insert(node);

                                System.out.println("in queue " + vertex[j]);
                            }
                        }
                    }
                }

            }
        }

    }
    return vertexList;
}

4.2.2 鄰接表的廣度優(yōu)先遍歷

??與鄰接矩陣相同,鄰接表的廣度優(yōu)先遍歷也借助隊列實現(xiàn),其中,逆鄰接表的實現(xiàn)會更為復(fù)雜:

/**
 * 對圖進(jìn)行廣度優(yōu)先遍歷
 *
 * @return 遍歷結(jié)果
 * @author Korbin
 * @date 2023-02-07 08:38:46
 **/
public List<T> breadthFirstTraverse() {

    List<T> vertexList = new ArrayList<>();

    boolean[] visited = new boolean[vertexNum];

    LinkQueue<Integer> queue = new LinkQueue<>();
    queue.init();

    for (int i = 0; i < vertexNum && vertexList.size() < vertexNum; i++) {

        System.out.println("iterate " + vertexes[i].getVertex());

        if (!visited[i]) {

            LinkListNode<Integer> node = new LinkListNode<>();
            node.setData(i);
            queue.insert(node);

            System.out.println("insert " + vertexes[i].getVertex());

            while (!queue.isEmpty() && vertexList.size() < vertexNum) {

                // 出隊列
                node = queue.delete();
                System.out.println("get " + vertexes[node.getData()].getVertex());

                int index = node.getData();
                VertexNode<T, W> vertexNode = vertexes[index];
                // 訪問該頂點
                if (!visited[index]) {
                    vertexList.add(vertexNode.getVertex());
                    visited[index] = true;

                    System.out.println("visit " + vertexNode.getVertex());

                    if (!reverseAdjacency) {
                        //  鄰接表
                        // 把指向的頂點一一入隊
                        EdgeNode<W> edge = vertexNode.getFirstEdge();
                        while (edge != null && vertexList.size() < vertexNum) {
                            index = edge.getIndex();
                            if (!visited[index]) {

                                System.out.println("insert " + vertexes[index].getVertex());

                                LinkListNode<Integer> childNode = new LinkListNode<>();
                                childNode.setData(index);
                                queue.insert(childNode);
                            }
                            edge = edge.getNext();
                        }
                    } else {
                        // 逆鄰表
                        // 把指向的頂點一一入隊
                        for (int j = 0; j < vertexNum && vertexList.size() < vertexNum; j++) {
                            if (j != index && !visited[j]) {
                                VertexNode<T, W> tmpVertex = vertexes[j];
                                EdgeNode<W> tmpEdge = tmpVertex.getFirstEdge();
                                while (null != tmpEdge && vertexList.size() < vertexNum) {
                                    if (tmpEdge.getIndex() == index) {
                                        // 入隊

                                        System.out.println(tmpEdge.getIndex() + "=======" + index + "=======" + j);

                                        System.out.println("insert " + vertexes[j].getVertex());

                                        LinkListNode<Integer> childNode = new LinkListNode<>();
                                        childNode.setData(j);
                                        queue.insert(childNode);
                                        break;
                                    }
                                    tmpEdge = tmpEdge.getNext();
                                }
                            }
                        }
                    }

                }

            }

        }

    }

    return vertexList;
}

4.2.3 十字鏈表的廣度優(yōu)先遍歷

??十字鏈表的實現(xiàn)與鄰接表的實現(xiàn)相同:

/**
 * 對圖進(jìn)行廣度優(yōu)先遍歷
 *
 * @return 遍歷結(jié)果
 * @author Korbin
 * @date 2023-02-07 09:56:29
 **/
public List<T> breadthFirstTraverse() {

    List<T> vertexList = new ArrayList<>();
    boolean[] visited = new boolean[vertexNum];

    LinkQueue<Integer> queue = new LinkQueue<>();
    queue.init();

    for (int i = 0; i < vertexNum && vertexList.size() < vertexNum; i++) {

        System.out.println("iterate " + vertexes[i].getVertex());

        if (!visited[i]) {

            LinkListNode<Integer> node = new LinkListNode<>();
            node.setData(i);
            queue.insert(node);

            System.out.println("insert " + vertexes[i].getVertex());

            while (!queue.isEmpty() && vertexList.size() < vertexNum) {

                // 出隊列
                node = queue.delete();
                System.out.println("get " + vertexes[node.getData()].getVertex());

                int index = node.getData();
                AcrossLinkVertexNode<T, W> vertexNode = vertexes[index];
                // 訪問該頂點
                if (!visited[index]) {
                    vertexList.add(vertexNode.getVertex());
                    visited[index] = true;

                    System.out.println("visit " + vertexNode.getVertex());

                    //  鄰接表
                    // 把指向的頂點一一入隊
                    AcrossLinkEdgeNode<W> edge = vertexNode.getFirstOut();
                    while (edge != null && vertexList.size() < vertexNum) {
                        index = edge.getHeadIndex();
                        if (!visited[index]) {

                            System.out.println("insert " + vertexes[index].getVertex());

                            LinkListNode<Integer> childNode = new LinkListNode<>();
                            childNode.setData(index);
                            queue.insert(childNode);
                        }
                        edge = edge.getNextHead();
                    }

                }

            }

        }

    }

    return vertexList;

}

4.2.4 鄰接多重表的廣度優(yōu)先遍歷

??上文有提到如何在鄰接多重表中尋找關(guān)聯(lián)的頂點,在進(jìn)行廣度遍歷時,同樣借助隊列實現(xiàn):

/**
 * 對圖進(jìn)行廣度優(yōu)先遍歷
 *
 * @return 遍歷結(jié)果
 * @author Korbin
 * @date 2023-02-07 10:03:26
 **/
public List<T> breadthFirstTraverse() {

    List<T> vertexList = new ArrayList<>();
    boolean[] visited = new boolean[vertexNum];

    LinkQueue<Integer> queue = new LinkQueue<>();
    queue.init();

    for (int i = 0; i < vertexNum && vertexList.size() < vertexNum; i++) {

        if (!visited[i]) {

            System.out.println("iterate " + vertexes[i].getVertex());

            // 入隊
            LinkListNode<Integer> node = new LinkListNode<>();
            node.setData(i);
            queue.insert(node);
            System.out.println("insert " + vertexes[i].getVertex());

            while (!queue.isEmpty() && vertexList.size() < vertexNum) {
                // 從隊列中取出
                int index = queue.delete().getData();
                System.out.println("get " + vertexes[index].getVertex());

                if (!visited[index]) {

                    // 訪問它
                    AdjacencyMultiVertexNode<T, W> vertexNode = vertexes[index];
                    vertexList.add(vertexNode.getVertex());
                    visited[index] = true;
                    System.out.println("visit " + vertexNode.getVertex());

                    // 取index關(guān)聯(lián)的頂點
                    AdjacencyMultiEdgeNode<W> firstEdge = vertexNode.getFirstEdge();
                    if (null != firstEdge) {
                        int childIndex = firstEdge.getJVex();

                        if (!visited[childIndex]) {
                            // 相關(guān)頂點入隊
                            LinkListNode<Integer> childNode = new LinkListNode<>();
                            childNode.setData(childIndex);
                            queue.insert(childNode);
                            System.out.println("insert " + vertexes[childIndex].getVertex());

                        }

                        AdjacencyMultiEdgeNode<W> edgeNode = firstEdge.getILink();
                        while (null != edgeNode && vertexList.size() < vertexNum) {

                            // 可能是iVex等于當(dāng)前頂點,也可能是jVex等于當(dāng)前頂點
                            int iVex = edgeNode.getIVex();
                            int jVex = edgeNode.getJVex();
                            if (iVex == index && !visited[jVex]) {
                                // 相關(guān)頂點是jVex
                                LinkListNode<Integer> childNode = new LinkListNode<>();
                                childNode.setData(jVex);
                                queue.insert(childNode);
                                System.out.println("insert " + vertexes[jVex].getVertex());
                            } else if (jVex == index && !visited[iVex]) {
                                // 相關(guān)頂點是iVex
                                LinkListNode<Integer> childNode = new LinkListNode<>();
                                childNode.setData(iVex);
                                queue.insert(childNode);
                                System.out.println("insert " + vertexes[iVex].getVertex());
                            }

                            edgeNode = edgeNode.getJLink();
                        }
                    }

                }
            }

        }

    }

    return vertexList;
}

4.2.5 邊集數(shù)組的廣度優(yōu)先遍歷

??邊集數(shù)組仍然需要多次迭代邊集數(shù)組,才能找到相關(guān)的頂點:

/**
 * 對圖進(jìn)行廣度優(yōu)先遍歷
 *
 * @return 遍歷結(jié)果
 * @author Korbin
 * @date 2023-02-07 10:30:36
 **/
public List<T> breadthFirstTraverse() {

    List<T> vertexList = new ArrayList<>();
    boolean[] visited = new boolean[vertexNum];

    LinkQueue<Integer> queue = new LinkQueue<>();
    queue.init();

    boolean[] visitedArc = new boolean[edgeNum];

    for (int i = 0; i < vertexNum && vertexList.size() < vertexNum; i++) {

        if (!visited[i]) {

            System.out.println("iterate " + vertex[i]);

            // 入隊
            LinkListNode<Integer> node = new LinkListNode<>();
            node.setData(i);
            queue.insert(node);
            System.out.println("insert " + vertex[i]);

            while (!queue.isEmpty() && vertexList.size() < vertexNum) {

                // 取出
                int index = queue.delete().getData();
                System.out.println("get " + vertex[index]);

                if (!visited[index]) {
                    // 訪問它
                    vertexList.add(vertex[index]);
                    visited[index] = true;
                    System.out.println("visit " + vertex[index]);

                    // 找它相關(guān)的頂點或指向的頂點

                    switch (type) {
                        case UNDIRECTED:
                        case UNDIRECTED_NETWORK: {
                            // 無向圖/網(wǎng)
                            for (int j = 0; j < edgeNum && vertexList.size() < vertexNum; j++) {
                                if (!visitedArc[j]) {

                                    System.out.println("iterate arc " + j);

                                    EdgeListEdgeNode<W> edge = arc[j];
                                    int begin = edge.getBegin();
                                    int end = edge.getEnd();

                                    if (begin == index) {
                                        if (!visited[end]) {
                                            // 入隊
                                            LinkListNode<Integer> childNode = new LinkListNode<>();
                                            childNode.setData(end);
                                            queue.insert(childNode);
                                            System.out.println("insert " + vertex[end]);
                                        }
                                    } else if (end == index) {
                                        if (!visited[begin]) {
                                            // 入隊
                                            LinkListNode<Integer> childNode = new LinkListNode<>();
                                            childNode.setData(begin);
                                            queue.insert(childNode);
                                            System.out.println("insert " + vertex[begin]);
                                        }
                                    }

                                    if (visited[begin] && visited[end]) {
                                        visitedArc[j] = true;
                                    }
                                }
                            }
                            break;
                        }
                        case DIRECTED:
                        case DIRECTED_NETWORK: {
                            for (int j = 0; j < edgeNum && vertexList.size() < vertexNum; j++) {
                                if (!visitedArc[j]) {

                                    System.out.println("iterate arc " + j);

                                    EdgeListEdgeNode<W> edge = arc[j];
                                    int begin = edge.getBegin();
                                    int end = edge.getEnd();

                                    if (begin == index && !visited[end]) {
                                        // 入隊
                                        LinkListNode<Integer> childNode = new LinkListNode<>();
                                        childNode.setData(end);
                                        queue.insert(childNode);
                                        System.out.println("insert " + vertex[end]);
                                    }

                                    if (visited[begin] && visited[end]) {
                                        visitedArc[j] = true;
                                    }
                                }
                            }
                            break;
                        }
                    }

                }

            }

        }

    }

    return vertexList;
}

??注意,邊集數(shù)組若不進(jìn)行特殊處理的話,每一層的頂點順序取決于邊集數(shù)組中結(jié)點順序的定義。,如下有向網(wǎng):

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??若定義為如下邊集數(shù)組時:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??廣度優(yōu)先遍歷過程為:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??廣度優(yōu)先遍歷結(jié)果為EADBFC。

??但如果把邊集數(shù)組的定義做一些調(diào)整:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??廣度優(yōu)先遍歷過程為:

圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷,數(shù)據(jù)結(jié)構(gòu),深度優(yōu)先,數(shù)據(jù)結(jié)構(gòu),寬度優(yōu)先

??遍歷結(jié)果為EADCBF,與之前的遍歷結(jié)果并不相同。

??當(dāng)然,你也可以選擇在取出所有相關(guān)的頂點后,對這些頂點按下標(biāo)排序,那么廣度優(yōu)先遍歷的結(jié)果就是固定的了,與邊集數(shù)組中結(jié)點的順序無關(guān)。

??注:本文為程 杰老師《大話數(shù)據(jù)結(jié)構(gòu)》的讀書筆記,其中一些示例和代碼是筆者閱讀后自行編制的。文章來源地址http://www.zghlxwxcb.cn/news/detail-756563.html

到了這里,關(guān)于大話數(shù)據(jù)結(jié)構(gòu)-圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包