算法导论实践——一看代码就会的BFS和DFS,贼刺激

算法导论实践——一看代码就会的BFS和DFS,贼刺激

  • 理论
  • C#实践
    • DFSSum.cs
    • BFSSum.cs
    • Program.cs

BFS和DFS的理论比较简单,直接看代码注释方可较为轻松地理解。本次实践以搜索子数组和为例。

理论

  • BFS,即广度优先搜索。下面,举一例说明。假设性感的小红被猛男层层包围(这里有三层)。小红要从中选择她的男朋友。假设她的择偶标准唯一——那就是长度(身高~手动滑稽)。那么小红运用广度优先算法择偶。那就先转一圈,看看第一层(最里层)猛男中有没有长度够的,如果没有,就继续去看第二层,在第二层,同样转一圈,一定要把每一个猛男都看一遍^ _ ^……第三层、第四层以此类推。
    算法导论实践——一看代码就会的BFS和DFS,贼刺激_第1张图片
  • DFS,即深度优先搜索。我们还是以小红和猛男为例。这次她用深度优先的算法寻找男朋友。那就是找到一个切入点,闷头冲。

算法导论实践——一看代码就会的BFS和DFS,贼刺激_第2张图片

  • 结论
    这就是DFS和BFS的基本思想,很简单。后面实践的例子并不是找男朋友。而是从数组A中,找和为n的子数组。不过这与找男朋友的情况也类似。
    假设我们有数组A = {1,2,3,4},我们想要找和为6的子数组。那么我们需要先选定根,也就是说,从哪里开始寻找。这就相当于我们需要选出谁是小红。我们假设位置1,也就是1是小红。这里的择偶标准就是,男朋友们与自己的和是否为6,那么他就应该找2,3号猛男,她全都要。于是,就转化成了我们之前说到的DFS和BFS思想了。好了,不多说了,直接上代码。
    算法导论实践——一看代码就会的BFS和DFS,贼刺激_第3张图片

C#实践

DFSSum.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace SearchStrategies
{
     
    public class DFSSum
    {
     
        /*演算:深度优先搜索集合A的子集,当且仅当该子集和为n时该子集是可行解
         * 
         * 深度优先搜索,即闷着头往前搜索,所以在递归路径上一直进站返回出栈即可
         * 
         */
        /// 
        /// 
        /// 
        /// 集合A
        /// 目标值
        /// 当前子集的和
        /// 当前的根结点
        private List<int> record = new List<int>();
        private bool flag;

        public void DFSSumStrategy(int[] A, int n, int sum, int root)
        {
     
            sum += A[root];
            record.Add(root);

            if(sum == n)
            {
     
                flag = true;    //找到了
                GetResult();	//输出元素
                return;
            }

            else if(sum < n)
            {
     
                for(int i = root + 1; i < A.Length; i++)
                {
     
                    DFSSumStrategy(A, n, sum, i);//找一路
                    record.Remove(i);	
                    //表明该路径不符号要求,因为回溯回来了,因此移除结点i
                }
            }
        }

        public void GetResult(int chooseRoot)
        {
     
            if(flag == false)
            {
     
                Console.WriteLine("在以" + chooseRoot + "为起始节点的情况下运用DFS" + ",则没有这种集合");
            }
        }

        public void GetResult()
        {
     
            for (int i = 0; i < record.Count; i++)
            {
     
                Console.Write(record[i]);
                Console.Write(" ");
            }
            Console.WriteLine(" ");
        }


    }
}

BFSSum.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace SearchStrategies
{
     
    public class BFSSum
    {
     
        /*演算:广度优先搜索集合A的子集,当且仅当该子集和为n时该子集是可行解
         * 
         * 广度优先搜索,即周围一圈都要搜索。
         * 
         */

        private List<Record> records = new List<Record>();  //记录队列
        private bool flag;
        public void BFSSumStrategy(int[] A, int n, int root)
        {
     
            AddRecord(root, A);
            while (records.Count != 0)
            {
     
                Record head = records[0];
                records.RemoveAt(0);

                //检查队首的Record,找到位于其路径末尾的结点,广度搜索末尾结点的周围结点
                for(int i = head.Path[head.Path.Count - 1] + 1; i < A.Length; i++)
                {
     
                    //head.Sum + A[i]如果小于n,
                    //那么将新建一条Record,该Record的Sum等于head.Sum + A[i]
                    //将这条Record加入到records中
                    if (head.Sum + A[i] < n)
                    {
     
                        AddRecord(head, head.Sum + A[i], i);
                    }
                    //如果大于了,那么就不管当前节点了,开始找下一个结点
                    else if(head.Sum + A[i] > n)
                    {
     
                        continue;
                    }
                    //表明找到了
                    else
                    {
     
                        flag = true;
                        //加入方便输出,不影响整体逻辑
                        AddRecord(head, head.Sum + A[i], i);
                        GetResult(records[records.Count - 1].Path);  
                    }
                }

                Console.WriteLine("当前记录队列长度"+records.Count);
            }

        }


        /// 
        /// 添加一条记录
        /// 
        /// 之前的记录
        /// 添加的结点的Sum
        /// 添加的结点的下标
        public void AddRecord(Record beforeRecord, int newRootSum, int newRoot)
        {
     
            Record newRecord = new Record
            {
     
                Sum = newRootSum,
                Path = new List<int>()
            };

            for (int i = 0; i < beforeRecord.Path.Count; i++)
            {
     
                newRecord.Path.Add(beforeRecord.Path[i]);
            }
			//在之前的记录的路径的基础上添加新节点的下标
            newRecord.Path.Add(newRoot);
			//将新的记录添加进记录队列中,以便下一次广度搜索
            records.Add(newRecord);
        }

        /// 
        /// 添加根节点
        /// 
        /// 根的下标
        /// 集合A
        public void AddRecord(int root, int[] A)
        {
     
            Record rootRecord = new Record
            {
     
                Sum = A[root],
                Path = new List<int>()
            };
            rootRecord.Path.Add(root);

            records.Add(rootRecord);
        }

        public void GetResult(List<int> record)
        {
     
            for (int i = 0; i < record.Count; i++)
            {
     
                Console.Write(record[i]);
                Console.Write(" ");
            }
            Console.WriteLine(" ");
        }

        public void GetResult(int chooseRoot)
        {
     
            if (flag == false)
            {
     
                Console.WriteLine("在以" + chooseRoot + "为起始节点的情况下运用BFS" + ",则没有这种集合");
            }
        }
    }

    /// 
    /// Record为每一条路径的记录,Sum为该路径的和
    /// Path为该路径上的结点下标
    /// 
    public class Record
    {
     
        public int Sum;
        public List<int> Path;
    }

}

Program.cs

using System;

namespace SearchStrategies
{
     
    class Program
    {
     
        static void Main(string[] args)
        {
     
            int[] A = {
      1, 5 ,4 ,2, 3, 2, 3 };
            for(int root = 0; root < A.Length; root++)
            {
     
                Console.WriteLine("===============我是分割线================ ");
                DFSSum dfsUtil = new DFSSum();
                dfsUtil.DFSSumStrategy(A, 9, 0, root);
                dfsUtil.GetResult(root);
                Console.WriteLine(" ");
            }

            Console.WriteLine("=======================我是BFS分割线=========================");
            Console.WriteLine(" ");
            
            
            for (int root = 0; root < A.Length; root++)
            {
     
                Console.WriteLine("===============我是分割线================ ");
                BFSSum bfsUtil = new BFSSum();
                bfsUtil.BFSSumStrategy(A, 9, root);
                bfsUtil.GetResult(root);
                Console.WriteLine(" ");
            }
        }
    }
}

你可能感兴趣的:(算法学习,队列,算法,数据结构,c#,经验分享)