C#--BFS广度优先搜索和DFS深度优先搜索

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq826364410/article/details/87372171

广度优先搜索(Breadth First Search,简称BFS)

从某个节点出发,首先访问这个节点,然后找出这个节点的所有未被访问的邻接点(或是孩子节点),访问完这些邻接点(或是孩子节点)后,再访问第一个邻接点(或是孩子节点)的所有未被访问的邻接点(或是孩子节点),重复此步骤,直到所有的节点都被访问完为止。如上图,广度优先搜索的顺序是:ABCDEFG

深度优先搜索(Depth First Search,简称DFS)

从某个节点出发,首先访问这个节点,然后找出这个节点的第一个未访问的邻接点(或是孩子节点),然后以这个邻接点(或是孩子节点)为新的出发点,继续寻找他的第一个未访问的邻接点(或是孩子节点),重复此步骤,直到所有的节点都被访问完为止。如上图,深度优先搜索的顺序是:ABDECFG

实例

现在以一个实际的例子用C#代码来实现,下面是Unity中的一个Hierarchy层级图,根节点是Root,下面有GameObject,GameObject (1), GameObject (2)三个节点,其中GameObject (1)下又有GameObject_A和GameObject_B两个节点:

using System.Collections.Generic;
using UnityEngine;

public class DM06Composite : MonoBehaviour
{
    void Start()
    {
        DMComposite root = new DMComposite("Root");
        // 添加Root下的三个节点
        DMLeaf leaf1 = new DMLeaf("GameObject");
        DMLeaf leaf2 = new DMLeaf("GameObject (2)");
        DMComposite gameObject1 = new DMComposite("GameObject (1)");
        root.AddChild(leaf1);
        root.AddChild(gameObject1);
        root.AddChild(leaf2);
        
        // 添加GameObject (1)下面的两个节点
        DMLeaf child1 = new DMLeaf("GameObject_A");
        DMLeaf child2 = new DMLeaf("GameObject_B");
        gameObject1.AddChild(child1);
        gameObject1.AddChild(child2);

        // 按照广度优先或深度优先输出节点顺序
        //DepthFirstSearch(root);
        BreadthFirstSearch(root);
    }

    // 广度优先检索
    private void BreadthFirstSearch(DMComponent component)
    {
        Queue<DMComponent> q = new Queue<DMComponent>();
        q.Enqueue(component);
        // 打印节点名字
        Debug.Log(component.Name);
        while (q.Count > 0)
        {
            DMComponent temp = q.Dequeue();
            List<DMComponent> children = temp.Children;
            foreach (DMComponent child in children)
            {
                // 打印节点名字
                Debug.Log(child.Name);
                q.Enqueue(child);
            }
        }
    }

    // 深度优先检索
    private void DepthFirstSearch(DMComponent component)
    {
        // 打印节点名字
        Debug.Log(component.Name);
        List<DMComponent> children = component.Children;
        if (children == null || children.Count == 0) return;
        foreach (DMComponent child in children)
        {
            DepthFirstSearch(child);
        }
    }
}

// 抽象组件类
public abstract class DMComponent
{
    protected string mName;
    public string Name { get { return mName; } }
    public DMComponent(string name)
    {
        mName = name;
        mChildren = new List<DMComponent>();
    }
    protected List<DMComponent> mChildren;
    public List<DMComponent> Children { get { return mChildren; } }
    public abstract void AddChild(DMComponent c);
    public abstract void RemoveChild(DMComponent c);
    public abstract DMComponent GetChild(int index);
}

// 叶子组件类
public class DMLeaf : DMComponent
{
    public DMLeaf(string name) : base(name) { }


    public override void AddChild(DMComponent c)
    {
        return;
    }

    public override void RemoveChild(DMComponent c)
    {
        return;
    }

    public override DMComponent GetChild(int index)
    {
        return null;
    }
}

// 容器组件类
public class DMComposite : DMComponent
{
    public DMComposite(string name) : base(name) { }


    public override void AddChild(DMComponent c)
    {
        mChildren.Add(c);
    }

    public override void RemoveChild(DMComponent c)
    {
        mChildren.Remove(c);
    }

    public override DMComponent GetChild(int index)
    {
        return mChildren[index];
    }
}

广度优先搜索:

扫描二维码关注公众号,回复: 5317571 查看本文章

深度优先搜索:

解析

上面的代码稍微有点复杂,下面详细的解释一下,首先,使用设计模式中的组合模式:组合多个对象形成树形结构,以表示具有“整体-部分”关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性。

抽象组件类(Component):它可以是接口或抽象类,为叶子组件和容器组件对象声明接口,在该角色中可以包含所有子类共有行为的声明和实现。在抽象组件类中,定义了访问及管理它的子组件的方法;

叶子组件类(Leaf):在组合模式中,表示叶子节点对象,叶子节点没有子节点,实现了在抽象组件类中定义的行为。

容器组件类(Composite):在组合模式中,表示容器节点对象,容器节点包含子节点,其子节点可以叶子节点,也可以是容器节点,提供了一个集合用于存储子节点,实现了在抽象组件类中定义的行为,包括访问及管理子组件的方法。

使用组合模式的目的是为了组装上面的层次结构,建立好层次结构后,就可以进行检索了。

广度优先搜索实现的核心思想:

建立一个队列Queue,利用它的先进先出原则,把根节点放入队列中,在一个while循环中,检索根节点的所有子节点,把根节点从队列中移除,然后把子节点放入队列中,检索子节点的所有子节点,依次循环执行。

深度优先搜索实现的核心思想:

首先遍历根节点的所有子节点,然后使用递归,依次遍历子节点下面的子节点。

猜你喜欢

转载自blog.csdn.net/qq826364410/article/details/87372171