ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

C# 实现DFS(深度优先遍历)的三种方式

2022-04-22 13:32:25  阅读:181  来源: 互联网

标签:Node head 遍历 C# DFS Right root stack Left


有一个美丽的传说:所有递归都能用循环代替——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();
            }
        }
 
    }
}

 

标签:Node,head,遍历,C#,DFS,Right,root,stack,Left
来源: https://www.cnblogs.com/SF8588/p/16178468.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有