递归和嵌套循环的区别

递归和嵌套循环的区别

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

递归和嵌套循环的区别

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);
                }

            }
        }