图的两种遍历算法(深度优先vs广度优先)

1.深度优先算法
  主要思路是从图中一个未访问的顶点 V 开始,沿着一条路一直走到底,然后从这条路尽头的节点回退到上一个节点,再从另一条路开始走到底...,不断递归重复此过程,直到所有的顶点都遍历完成,它的特点是不撞南墙不回头,先走完一条路,再换一条路继续走
2.广度优先算法
  某个顶点出发,首先访问这个顶点,然后找出这个结点的所有未被访问的邻接点,访问完后再访问这些结点中第一个邻接点的所有结点,重复此方法,直到所有结点都被访问完为止

C#实现:

基础定义:

    public class NodeInfo
    {
        /// <summary>
        /// 节点ID
        /// </summary>
        public int Id { get; set; } = 0;

        /// <summary>
        /// 是否被遍历过
        /// </summary>
        public bool Visited { get; set; } = false;

        /// <summary>
        /// 临接元素的id
        /// </summary>
        public int[] Neighbors { get; set; } = null;

        /// <summary>
        /// 构造函数
        /// </summary>
        public NodeInfo()
        {

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="neighbors"></param>
        public NodeInfo(int id, int[] neighbors)
        {
            Id = id;
            Neighbors = neighbors;
        }
    }


    public class TreeInfo
    {
        /// <summary>
        /// 节点列表
        /// </summary>
        public List<NodeInfo> Nodes = new List<NodeInfo>();

        /// <summary>
        /// 填入tree中
        /// </summary>
        /// <param name="node"></param>
        public void Append(NodeInfo node)
        {
            if (node == null)
            {
                return;
            }
            Nodes.Add(node);
        }

        /// <summary>
        /// 首个节点
        /// </summary>
        /// <returns></returns>
        public NodeInfo First()
        {
            return Nodes?.FirstOrDefault();
        }

        /// <summary>
        /// 搜索指定节点相邻节点
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        public List<NodeInfo> FindNeibors(NodeInfo node)
        {
            List<NodeInfo> list = new List<NodeInfo>();
            foreach (var nx in node.Neighbors)
            {
                list.Add(Nodes.FirstOrDefault(k => k.Id == nx));
            }
            return list;
        }
    }

 

 

算法实现:

    /// <summary>
    /// 遍历树算法(深度优先 广度优先)
    /// </summary>
    public class TreeVisit
    {

        /// <summary>
        /// 测试遍历
        /// </summary>
        public static void Test()
        {
            TreeInfo tree = new TreeInfo();
            tree.Append(new NodeInfo(1, new int[] { 3, 2, 4 }));
            tree.Append(new NodeInfo(2, new int[] { 1, 5, 8, 300 }));
            tree.Append(new NodeInfo(3, new int[] { 1, 7, 9, 100 }));
            tree.Append(new NodeInfo(4, new int[] { 1, 6, 10, 200 }));
            tree.Append(new NodeInfo(5, new int[] { 2 }));
            tree.Append(new NodeInfo(6, new int[] { 4 }));
            tree.Append(new NodeInfo(7, new int[] { 3 }));
            tree.Append(new NodeInfo(8, new int[] { 2 }));
            tree.Append(new NodeInfo(9, new int[] { 3, 400 }));
            tree.Append(new NodeInfo(10, new int[] { 4 }));
            tree.Append(new NodeInfo(100, new int[] { 3 }));
            tree.Append(new NodeInfo(200, new int[] { 4 }));
            tree.Append(new NodeInfo(300, new int[] { 2 }));
            tree.Append(new NodeInfo(400, new int[] { 9,700 }));
            tree.Append(new NodeInfo(700, new int[] { 400 }));
            DFS(tree, tree.First());
            //GFS(tree, tree.First());

        }

        /// <summary>
        /// 深度优先遍历
        /// </summary>
        /// <param name="tree"></param>
        /// <param name="startNode"></param>
        public static void DFS(TreeInfo tree, NodeInfo startNode)
        {
            List<NodeInfo> path = new List<NodeInfo>();
            path.Add(startNode);
            List<NodeInfo> b = new List<NodeInfo>();
            b.Add(startNode);
            startNode.Visited = true;
            Console.WriteLine(startNode.Id);
            NodeInfo a = new NodeInfo();
            while (b.Count != 0)
            {
                //找到节点的相邻节点取第一个没有访问过的节点
                a = tree.FindNeibors(b[b.Count - 1]).FirstOrDefault(k => !k.Visited);
                while (a != null)
                {
                    b.Add(a);
                    Console.WriteLine(a.Id);
                    path.Add(a);
                    a.Visited = true;
                    //一直遍历元素的第一个节点直到没有子节点
                    a = tree.FindNeibors(b[b.Count - 1]).FirstOrDefault(k => !k.Visited);
                }
                if (a == null) //没有子节点就删除这个节点 取上一个节点的未被访问过的节点
                {
                    b.Remove(b[b.Count - 1]);//删除最后一个
                }
            }
        }

        /// <summary>
        /// 广度优先(利用队列先进先出的规则)
        /// </summary>
        /// <param name="tree"></param>
        /// <param name="startNode"></param>
        public static void GFS(TreeInfo tree, NodeInfo startNode)
        {
            Queue<NodeInfo> b = new Queue<NodeInfo>();
            b.Enqueue(startNode);
            List<NodeInfo> nodeList = new List<NodeInfo>() { startNode };
            while (b.Count > 0)
            {
                var mq = b.Dequeue();
                mq.Visited = true;
                Console.WriteLine(mq.Id);
                var neibors = tree.FindNeibors(mq)?.Where(m => !m.Visited).ToList() ?? new List<NodeInfo>();
                if (neibors.Count > 0)
                {
                    neibors.ForEach(m =>
                    {
                        b.Enqueue(m);
                        nodeList.Add(m);
                    });
                }
            }
        }

    }

 

posted @ 2022-06-16 10:42  小布雷  阅读(140)  评论(0编辑  收藏  举报