圖的遍歷一般有兩種方式:深度優先和廣度優先。
深度優先(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;
}
}