圖的遍歷:深度優先遍歷和廣度優先遍歷

圖的遍歷一般有兩種方式:深度優先和廣度優先。

深度優先(DFS)

深度優先遍歷也叫深度優先搜索(Depth First Search)。它的遍歷規則:不斷地沿着頂點的深度方向遍歷。頂點的深度方向是指它的鄰接點方向。

具體點,給定一圖G=<V,E>,用visited[i]表示頂點i的訪問情況,則初始情況下所有的visited[i]都爲false。假設從頂點V0開始遍歷,則下一個遍歷的頂點是V0的第一個鄰接點Vi,接着遍歷Vi的第一個鄰接點Vj,……直到所有的頂點都被訪問過。

“第一個”是指在某種存儲結構中(鄰接矩陣、鄰接表),所有鄰接點中存儲位置最近的,通常指的是下標最小的。按照某種規律的第一個。

遍歷過程中通常有兩種情況:
1、某個頂點的鄰接點都已被訪問過的情況,此時需回溯已訪問過的頂點。
2、圖不連通,所有的已訪問過的頂點都已回溯完了,仍找不出未被訪問的頂點。此時需從下標0開始檢測visited[i],找到未被訪問的頂點i,從i開始新一輪的深度搜索。

一般而言,接觸到的大部分是連通圖。

示例

在這裏插入圖片描述
從V0開始遍歷:
遍歷分析:V0有兩個鄰接點V1和V2,選擇下標最小的V1遍歷。接着從V1開始深度遍歷,V1只有鄰接點V3,也就是沒有選的:遍歷V3。接着從V3開始遍歷,V3只有鄰接點V0,而V0已經被遍歷過。此時出現了上面提到的情況一,開始回溯V1,V1無未被遍歷的鄰接點,接着回溯V0,V0有一個未被遍歷的鄰接點V2,新的一輪深度遍歷從V2開始。V2無鄰接點,且無法回溯。此時出現了情況二,檢測visited[i],只有V4了。深度遍歷完成。
遍歷序列是
V0->V1->V3->V2->V4。

實現(二叉樹爲例)

一般回溯的實現可以使用,也可以遞歸

棧實現:

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/

public class Solution {
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
        ArrayList<Integer> lists=new ArrayList<Integer>();
        if(root==null)
            return lists;
        Stack<TreeNode> stack=new Stack<TreeNode>();
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode tree=stack.pop();
      //先往棧中壓入右節點,再壓左節點,這樣出棧就是先左節點後右節點了。
            if(tree.right!=null)
                stack.push(tree.right);
            if(tree.left!=null)
                stack.push(tree.left);
            lists.add(tree.val);
        }
        return lists;
    }
}

遞歸實現

實際上是樹的先序遍歷

public void depthOrderTraversalWithRecursive()  
    {  
        depthTraversal(root);  
    }  
      
    private void depthTraversal(TreeNode tn)  
    {  
        if (tn!=null)   
        {  
            System.out.print(tn.value+"  ");  
            depthTraversal(tn.left);  
            depthTraversal(tn.right);  
        }         
    }

廣度優先(BFS)

廣度優先遍歷也叫廣度優先搜索(Breadth First Search)。它的遍歷規則:
1、先訪問完當前頂點的所有鄰接點。(應該看得出廣度的意思)
2、先訪問頂點的鄰接點先於後訪問頂點的鄰接點被訪問。

具體點,給定一圖G=<V,E>,用visited[i]表示頂點i的訪問情況,則初始情況下所有的visited[i]都爲false。假設從頂點V0開始遍歷,且頂點V0的鄰接點下表從小到大有Vi、Vj…Vk。按規則1,接着應遍歷Vi、Vj和Vk。再按規則2,接下來應遍歷Vi的所有鄰接點,之後是Vj的所有鄰接點,…,最後是Vk的所有鄰接點。接下來就是遞歸的過程…

在廣度遍歷的過程中,會出現圖不連通的情況,此時也需按上述情況二來進行:測試visited[i]…。

示例

在這裏插入圖片描述
從V0開始遍歷
遍歷分析:V0有兩個鄰接點V1和V2,於是按序遍歷V1、V2。V1先於V2被訪問,於是V1的鄰接點應先於V2的鄰接點被訪問,那就是接着訪問V3。V2無鄰接點,只能看V3的鄰接點了,而V0已被訪問過了。此時需檢測visited[i],只有V4了。廣度遍歷完畢。
遍歷序列是
V0->V1->V2->V3->V4。

實現(二叉樹爲例)

一般可以使用隊列。(就是樹的層次遍歷)

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/

public class Solution {
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
        ArrayList<Integer> lists=new ArrayList<Integer>();
        if(root==null)
            return lists;
        Queue<TreeNode> queue=new LinkedList<TreeNode>();
        queue.offer(root);
        while(!queue.isEmpty()){
            TreeNode tree=queue.poll();
            if(tree.left!=null)
                queue.offer(tree.left);
            if(tree.right!=null)
                queue.offer(tree.right);
            lists.add(tree.val);
        }
        return lists;
    }
}

參考:
深度優先遍歷和廣度優先遍歷
樹的深度優先遍歷和廣度優先遍歷java實現

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章