CS2L10——递归函数
递归
所谓递归,就是让函数自己调用自己
注意,错误的递归函数(或者说没有终止条件的递归)会无限递归导致爆栈!
1 2 3 4 5 6 7 8 9
| static void Fun() { Fun(); }
static void Main(string[] args) { Fun(); }
|
报错:
1 2 3 4 5 6
| Stack overflow. Repeat 24088 times: -------------------------------- at lesson11递归函数.Program.Fun() -------------------------------- at lesson11递归函数.Program.Main(System.String[])
|
一个正确的递归函数,必须要有结束调用的条件!
用于条件判断的 这个条件 必须改变 能够达到停止的目的
例如,用递归函数打印出 0 到 10
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| static void Fun(int a) { Console.WriteLine(a); ++a; if (a > 10) { return; } Fun(a); }
static void Main(string[] args) { Fun(0); }
|
输出:
1 2 3 4 5 6 7 8 9 10 11
| 0 1 2 3 4 5 6 7 8 9 10
|
关于递归和循环
要注意,递归不是循环!循环是反复执行一段代码,执行结束回到开头,而递归是在函数执行途中调用自己,执行期间回到开头
只是有些递归可以优化为循环,例如尾递归,尾递归指的是函数在尾位置调用自身,
上例就是尾递归,这样的递归常可以优化为循环,优秀的编译器会在编译时自动优化。
而某些递归则不容易优化为循环,或者改为循环反而降低性能或者徒增代码量,例如,遍历文件树
假设有这样的数组,数组内部有字符串,或者字符串数组,字符串数组还可能嵌套数组,遍历这个数组中的所有字符串并输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| static void TraverseString(object[] array) { for (int i = 0; i < array.Length; ++i) { if (array[i] is object[]) { TraverseString((object[])array[i]); } else { Console.WriteLine(array[i]); } } }
static void Main(string[] args) { object[] tree = { "aaaa", "bbbb", new object[] { "ccccaaaa", "ccccbbbb" }, "dddd", "eeee", new object[] { "ffffaaaa", "ffffbbbb", new object [] { "ffffccccaaaa", "ffffccccbbbb" } }, "gggg", };
TraverseString(tree); }
|
输出:
1 2 3 4 5 6 7 8 9 10 11
| aaaa bbbb ccccaaaa ccccbbbb dddd eeee ffffaaaa ffffbbbb ffffccccaaaa ffffccccbbbb gggg
|
上例中的数据集合就很适合使用递归去遍历整个数组的字符串,尤其是嵌套层数不确定的时候,使用递归会简化很多代码量