递归和嵌套循环的区别
亲,不要误以为自己调用自己就等于递归了!
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); } } }