• 递归和嵌套循环的区别


    递归和嵌套循环的区别

    亲,不要误以为自己调用自己就等于递归了!

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    
    namespace TreeSearch
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void btnSearch_Click(object sender, EventArgs e)
            {
                //查询前折叠所有
                trv.CollapseAll();
    
                //关键字
                string keyStr = txtKey.Text.Trim();
    
                //遍历根节点
                foreach (TreeNode tn in trv.Nodes)
                {
                    CheckNode(tn, keyStr);
                    FindChildNode(tn, keyStr);
                }
            }
    
            /// <summary>
            /// 遍历子节点
            /// </summary>
            /// <param name="tnParent">当前节点</param>
            /// <param name="keyStr">关键字</param>
            void FindChildNode(TreeNode tnParent, string keyStr)
            {
                foreach (TreeNode tn in tnParent.Nodes)
                {
                    CheckNode(tn, keyStr);
    
                    //递归检查当前节点的子节点
                    FindChildNode(tn, keyStr);
                }
            }
    
            /// <summary>
            /// 展示符合条件的节点
            /// </summary>
            /// <param name="tn"></param>
            void DisplayNode(TreeNode tn)
            {
                if (tn.Parent != null)
                {
                    tn.Parent.Expand();
                    DisplayNode(tn.Parent);
                }
            }
    
            /// <summary>
            /// 检测当前节点
            /// </summary>
            /// <param name="tn"></param>
            /// <param name="keyStr"></param>
            void CheckNode(TreeNode tn, string keyStr)
            {
                //包含关键字,变红并展示节点
                if (tn.Text.Contains(keyStr))
                {
                    tn.ForeColor = Color.Red;
                    DisplayNode(tn);
                }
                else
                {
                    //代替初始化的操作方法
                    tn.ForeColor = Color.Black;
                }
            }
    
    
            //从低往高加
            public int sum23(int param)
            {
                int sum = 0;
                for (int i = 0; i < param; i++)
                {
                    sum += 1;
                }
                return sum;
            }
    
            //从高往第加
            public int sum1(int param)
            {
                int sum = 0;
                for (int i = param; i >= 0; i--)
                {
                    sum += i;
                }
                return sum;
            }
    
    
            public int sum(int param)
            {
                if (param == 0) { return 0; }
                else
                {
                   return  param += sum(param-1);
                }
            }
    
            public long Fac(int n)
            {
                if (n == 0)
                {
                    return 1;
                }
                else
                {   //用for循环来不断的叠乘
                    long value = 1;
                    for (int i = n; i > 0; i--)
                    {
                        value *= 1;
                    }
                    return value;
                }
    
            }
    
    
        }
    }

     其实,我也不知道第一种情况算不算严格意义上滴递归滴呀;

    下面的方法是另外的一种方式来实现滴呀;

     void FindChildNode2(TreeNode tnParetn, string KeyStr)
            {
                int len = tnParetn.Nodes.Count;
                for (int i = 0; i < len; i++)
                {
                   TreeNode tn= tnParetn.Nodes[i];
                   if (tn == null)
                   {
                       break;   //种方式也是也已滴一  //这个就算是遍历了一颗节点数滴呀;
                                //这种到底算不算是递归呢?
                   }
                   else
                   {
                       CheckNode(tn, KeyStr);
                       FindChildNode2(tn, KeyStr); //就等于这样一种形式滴呀;
                   }
                }
            }

    后面,我对递归由进一步的研究了,然后发现,我的结论可能是错的;!!!

    我们来看两种递归的执行情况;

    没有返回值,仅仅是又我们的临界值;

            /// <summary>
            ///  相当于一个进栈和出栈的过程;当达到临界值之后,就会回到开始点;
            ///  进行出栈;
            /// </summary>
            /// <param name="n"></param>
            public static  void CallSelf(int n)
            {
                if (n > 0)
                {
                    Console.WriteLine(n+" in");
                    CallSelf(--n); 
                    Console.WriteLine(n+" out");
                }
    
            }

     它的执行过程,可以这么理解:

     

    或者,你可以这么理解它;

     

    我擦,流程有够丑的,不过相当直观了,如果还不太清楚,你可以自己调试一哈,跟着走一遍,就会有较为深刻的理解了;

    这里再贴出一个fibo数的实现过程;

     然后,我们来看一个,有返回值的递归;

            /// <summary>
            /// call themself with return
            /// </summary>
            /// <param name="n"></param>
            /// <returns></returns>
            public static int CallSelfWithReturn(int n)
            {
                if (n == 0)
                {
                    return 0;
                }
                Console.WriteLine(n);
                return CallSelfWithReturn(--n);//又重新回到这个点;
    
            }

    对这里个理解,我们就可以使用,可以用第一个图来进行解释,因为,这里有一个关键点;就是它会保存,当时执行时的一些变量信息;当回到递归的开始点时,又你能用到但是的些变量值;(这个是非常重要的点;)

    我们再来看他隐身出的一些列的问题:

            //总的来说,它是利用了大顶堆的特性;
            //一个完整的堆定二叉树,堆定都是一个最大的数据;
            //每次从堆定取出一个数,然后此时堆,新的堆序列又乱了,然后有开始进行重新调整;然后
            //堆栈,它每次回记得调用后的,当时的数据,以便在回到这个点的时候,继续进行;
    
           //而同样的方法,我们可以使用for循环来实现;
           public static void ForEachImple(int n)
            {
                int loopTimes = n;
                for(int i = 0; i <= loopTimes; i++)
                {
                    Console.WriteLine(n);
    
                    n = n - 1;
                }
    
            }
    
            /// <summary>
            /// 其实,我们的递归方式,更像这种方式来执行的;
            /// </summary>
            /// <param name="n"></param>
            public static void ForEachImple2(int n)
            {
                //同样的方式,我们也可以这样来实现;
                for(int i = 0; i < 1; i++)
                {
                    int loop0 = n; //当前栈的变量值
                    Console.WriteLine(loop0);
                    n = n - 1;
                    for (int j = 0; j < 1; j++)
                    {
                        int loop1 = n;//当前栈的变量值
                        Console.WriteLine(loop1);
                        n = n - 1;
                        for (int k = 0; k < 1; k++)
                        {
    
                            int loop2 = n;//当前栈的变量值
                            Console.WriteLine(loop2);
                            n = n - 1;
                        }
    
                    }
    
                }
            }
    
            //所以我们再遍历,node的时候,常常会写出这样的代码;
            //我想看他是如何如构造一颗树滴呀;
    
            public static List<Node> CreateNodes()
            {
    
                Node node0 = new Node()
                {
                    Id = 1,
                    PId = 0,
                    Name = "Nike",
                    Childrends = new List<Node>()
                    {
                        new Node() {
                        Id = 2,
                        PId =1,
                        Name = "air jordan1"
                        },
                        new Node() {
                        Id = 3,
                        PId =1,
                        Name = "air jordan2"
                        }
    
                    }
                };
    
                Node node1 = new Node()
                {
                    Id = 4,
                    PId = 0,
                    Name = "Adidas",
                };
    
    
                Node nodeTop = new Node()
                {
                    Id = 5,
                    PId = -1,  //顶级top 节点;
                    Name = "sport brand",
                    Childrends = new List<Node>() { node0, node1 }
                };
    
    
                List<Node> list = new List<Node>();
                list.Add(nodeTop);
    
    
                return list;
    
    
            }
    
            public static void Iteori()
            {
    
    
    
    
    
                //然后当我们去遍历一个可树的时候,通常我们会这样写;
    
                //先遍历第一节;
                //然后再遍历第二节
                //然后遍历第三节;
                //这样,我们就可能写出三个嵌套的for循环;每个循环负责遍历一个节点;
                List<Node> list = CreateNodes();
    
    
    
                //foreach(var TopNode in list)
                //{
    
                //    foreach(var SecondeNode in TopNode.Childrends)
                //    {
    
                //        foreach(var thirdNode in SecondeNode.Childrends)
                //        {
    
                //            //如果这样的写的话,我们是先从叶子节点,开始遍历的,当叶子节点遍历完之后,又开始上一级的比那里;
                //            //Console.WriteLine(thirdNode.Name);
    
                //            //还不能这么写,如果这么写的,话 里面的执行次数,将是TopNode.length*SecondeNode.length*thirdNode.length
                //            //所以这样遍历是错误的;
    
                //        }
    
                //    }
                //}
    
    
                ///有节点,我们才进入我们的子节点中去进行遍历,这个相当于我们的左节点遍历;
                //然后,我们就就有了下面的遍历方式:遍历的深度,无法动态的扩展
    
                foreach (var TopNode in list)
                {
                    Console.WriteLine(TopNode.Name);
                    if (TopNode.Childrends!=null && TopNode.Childrends.Any())
                    {
                        foreach (var SecondeNode in TopNode.Childrends)
                        {
                             Console.WriteLine("  " + SecondeNode.Name);
    
                            if (SecondeNode.Childrends!=null && SecondeNode.Childrends.Any())
                            {
                                foreach (var thirdNode in SecondeNode.Childrends)
                                {
                                    Console.WriteLine("      "+thirdNode.Name);
    
                                }
                            }
    
                        }
                    }
                }
    
    
    
                //那么还有没有更好的方式去进行遍历呢; 
          }
    
        //就这样简单的试炼我们 节点的遍历;(其实,这个就是我们的前序遍历的实现)
        public  static void NodeItmeor(List<Node> nodes)
            {
                foreach (var topNode in nodes)
                {
                    //第一季,也就是我们的顶级;
                    Console.WriteLine(topNode.Name);
                    if(topNode.Childrends!=null && topNode.Childrends.Any())
                    {
                        NodeItmeor(topNode.Childrends);   //这样就形成了我们的迭代;遍历;
                    }
    
                }
    
            }

     其实,在开发中,我们常常遇到这样的场景;具有父子节点的集合(类似tree的结构);这个时候,我们需要把它组装成符合tree nodes(能体现出层级关系的nodes关系图);

    下面我们看具体的实例;

      /// <summary>
            /// 实际的测试方法;
            /// 相当管用滴呀;
            /// </summary>
            public static void Test()
            {
                List<Node> listNodes = new List<Node>()
                 {
                 new Node() { Id = 1, PId=0,Name="Nike" },
                 new Node() { Id = 2, PId = 1, Name = "Air Jordan系列" },
                 new Node() { Id = 3, PId = 2, Name = "Air Jordan 1" },
                 new Node() { Id = 4, PId = 2, Name = "Air Jordan 2" },
                 new Node() { Id = 5, PId = 1, Name = "Air Force系列" },
                 new Node() { Id = 6, PId = 5, Name = "Air Force 1" },
                 new Node() { Id = 7, PId = 0, Name = "Adidas" }
                };
    
                var pNodes = listNodes.Where(o=>o.PId==0).ToList();
                var Childrends = listNodes.Where(o=>o.PId!=0).ToList();
                foreach (var topNode in pNodes)
                {
                    FindChild(topNode, Childrends);
                }
              
            }
    
            /// <summary>
            /// /
            /// </summary>
            /// <param name="parentNode"></param>
            /// <param name="nodes"></param>
           public static void  FindChild(Node parentNode, List<Node> nodes)
            {
                //在集合中去寻找自己的子节点;
               var childs=nodes.Where(o=>o.PId==parentNode.Id).ToList();
                if(childs!=null && childs.Any())
                {
                    parentNode.Childrends = new List<Node>();
                    parentNode.Childrends.AddRange(childs);
                    foreach (var p in childs)  //继续查找,孩子节点的,子节点;
                    {
                        FindChild(p, nodes);
                    }
    
                }
            }
  • 相关阅读:
    【CF1043C】Smallest Word(构造)
    【CF1043B】Lost Array(枚举)
    【CF1043A】Elections(签到)
    【Codeforces Round #519】
    【HDOJ5556】Land of Farms(最大团)
    【HDOJ1828&&POJ1177】Picture(线段树,扫描线)
    【SPOJ61】Brackets(线段树)
    lgy -oracle
    虚拟机软件VMware Workstation Pro的安装与使用
    [技巧] 解决Win7下VMware中vmx86.sys报错的问题
  • 原文地址:https://www.cnblogs.com/mc67/p/5114008.html
Copyright © 2020-2023  润新知