1. 程式人生 > 其它 >C# 實現DFS(深度優先遍歷)的三種方式

C# 實現DFS(深度優先遍歷)的三種方式

有一個美麗的傳說:所有遞迴都能用迴圈代替——DFS、Backtracking也不例外……真的是這樣嗎?今天就為您揭開迷底!

正文

using System;
using System.Collections.Generic;
using System.Linq;
 
namespace HelloRider
{
    // 二叉樹結點
    class Node
    {
        public int Val { get; set; } //
        public Node Right { get; set; } // 右子樹
        public Node Left { get
; set; } // 左子樹 // 結點建構函式 public Node(int val) { Val = val; } } class Program { static void Main(string[] args) { Node root = BuildTree(); DFS_BTVersion(root); Console.ReadKey(); }
// 構建一個二叉樹 static Node BuildTree() { var root = new Node(1); root.Left = new Node(2); root.Left.Left = new Node(4); root.Left.Right = new Node(5); root.Right = new Node(3); root.Right.Left = new Node(6); root.Right.Right
= new Node(7); return root; } // 遞迴前序遍歷 static void DFS1(Node root) { if (root == null) { return; } Console.WriteLine(root.Val); DFS1(root.Left); DFS1(root.Right); } // 迴圈版前序遍歷,但是有個缺陷就是不能方便的實現中序和後序 static void DFS2(Node root) { var stack = new Stack<Node>(); stack.Push(root); while (stack.Count > 0) { var head = stack.Pop(); Console.WriteLine(head.Val); if(head.Right != null) stack.Push(head.Right); if(head.Left != null) stack.Push(head.Left); } } // 先了解一下BackTrading 回溯獲取所有路徑,再來學習用BT做DFS static List<List<Node>> BT(Node root) { var result = new List<List<Node>>(); // 儲存所有路徑 var stack = new Stack<Node>(); // 儲存單條路徑 var set = new HashSet<Node>(); // 單獨建立一個集合用來判斷某個結點是否訪問過 stack.Push(root); while (stack.Count > 0) { var head = stack.Peek(); // 獲取棧頂結點,peek不會刪除棧頂結點(與pop的區別) // 如果左結點不為空且沒有訪問過 if (head.Left != null && set.Add(head.Left)) { // 則將結點加入路徑 stack.Push(head.Left); continue; } if (head.Right != null && set.Add(head.Right)) { stack.Push(head.Right); continue; } // 左右結點都為空,則為一條完整的路徑 if (head.Left == null && head.Right == null) { var path = new List<Node>(stack); path.Reverse();// 由於棧是先進後出的,裡面的結點是逆序儲存的,所以需要將路徑反轉一下 result.Add(path); } // 返回上一結點 stack.Pop(); } return result; } // BT版的DFS(完整版,可以方便的做先序、中序、後序) static void DFS_BTVersion(Node root) { var stack = new Stack<Node>(); var set = new HashSet<Node>(); var accessed = new HashSet<Node>(); // 控制結點的輸出,如果該結點之前已經輸出過則不再輸出 stack.Push(root); while (stack.Count > 0) { var head = stack.Peek(); // 此處輸出為先序遍歷 if (accessed.Add(head)) Console.WriteLine(head.Val); if (head.Left != null && set.Add(head.Left)) { stack.Push(head.Left); continue; } // 此處輸出為中序遍歷 // if (accessed.Add(head)) // Console.WriteLine(head.Val); if (head.Right != null && set.Add(head.Right)) { stack.Push(head.Right); continue; } // 此處輸出為後序遍歷 // if (accessed.Add(head)) // Console.WriteLine(head.Val); stack.Pop(); } } } }