算法4讲到归并排序,也算是这本书对分治的介绍开始。分治的核心是递归,递归的思想则是大事化小,小事化了,这个“了”说明一定会有结束并开始回归。提到递归,我想很多人会和我一样,非常头疼,简单的那种尾递归,然后就一层,理解起来还是比较容易的,这个容易其实是建立在你可以思考跟踪程序的运算流程来理解。但是复杂的递归则就没那么容易理解了,因为你通过流程分析真的太难了,也可能是我比较笨吧。
首先举几个简单的例子,最简单也是最容易反馈递归特性的一个例子就是!,阶乘:
private static int factorial(int n) { if (n == 1) return 1;//开始回归 return n * (n - 1); }
这种是典型的尾递归,什么是尾递归呢,就是如果一个函数中所有递归形式的调用都出现在函数的末尾,我们称这个递归函数是尾递归的。当递归调用是整个函数体中最后执行的语句且它的返回值不属于表达式的一部分时,这个递归调用就是尾递归。尾递归函数的特点是在回归过程中不用做任何操作,这个特性很重要,因为大多数现代的编译器会利用这种特点自动生成优化的代码。
这种递归不仅方便我们理解,也能提高计算机效率。我们接下来深入一点点,写一个用二分法求最小值的一个递归:
private static int getMin(int[] arr, int l, int r) { if (l == r) {//最小的区间了 return arr[l];//开始回归 } else { int mid = l + ((r - l) >> 1); int left = getMin(arr, l, mid); int right = getMin(arr, mid + 1, r); int min = Math.min(left, right); return min; } }
这段代码我为了方便理解,把它给拆分开处理了,此时你若是脑袋里面去模拟整个程序的运行流程,容易绕晕,这个时候就可以用分治的思想去理解,你首先直接把当前函数getMin()作为一个固定值去处理,虽然他会不断的调用自己去运算,但是结果肯定会返回一个值给你,此时一定要宏观去思考left就是左边的这“一个”值,那么right也是同样的理解,这么min就是left和right当中较小的一个值。
这种思想去理解树的遍历,汉诺塔,归并,快排等等,其实理解起来会感觉很神奇,会感觉递归真的太美妙了,那么朦胧却又精致的美。关于递归的深入理解我后面还会在此基础上继续思考,这篇说了不算完整和精简,只是一时兴起,记录下,后面有新的思考会继续补充,若有不足也希望各位大佬指出,大家一起加油!