WEBVTT 00:00:00.060 --> 00:00:02.540 我在这集视频里想要做的是 讲清楚 00:00:02.540 --> 00:00:05.100 “跌代”与递归之间的差别 00:00:05.100 --> 00:00:06.870 或者我应该说迭代 00:00:06.870 --> 00:00:10.550 我总是发音错误- 迭代函数的定义 00:00:10.550 --> 00:00:15.900 与递归函数定义的差别 00:00:15.900 --> 00:00:18.030 我们会通过这样的方法来完成比较 00:00:18.030 --> 00:00:21.030 理解这边的迭代函数是怎么样工作的 00:00:21.030 --> 00:00:23.780 以及右边这个递归函数是怎么样工作的 00:00:23.780 --> 00:00:25.260 那么当我们开始的时候 00:00:25.260 --> 00:00:28.030 会看到product被设置成1 00:00:28.030 --> 00:00:29.940 然后进入到for循环里 00:00:29.940 --> 00:00:33.880 而for循环实际上是 00:00:33.880 --> 00:00:36.200 迭代函数定义的“肉” 00:00:36.200 --> 00:00:38.820 而为了理解for循环里发生了什么 00:00:38.820 --> 00:00:40.060 我在这里做一个表格 00:00:40.060 --> 00:00:43.950 我给变量i的值做一个表格 00:00:43.950 --> 00:00:46.260 并且我也会找出 00:00:46.260 --> 00:00:53.730 变量product乘以i+1的值是什么 00:00:53.730 --> 00:00:56.550 因为在for循环的每次迭代中 00:00:56.550 --> 00:00:58.970 我们都会计算这里这个表达式的值 00:00:58.970 --> 00:01:01.310 然后我会给product的新值 00:01:01.310 --> 00:01:03.480 也做出一列表格 00:01:03.480 --> 00:01:06.830 product的新值 00:01:06.830 --> 00:01:09.030 我给它们标上下划线 00:01:09.030 --> 00:01:12.100 然后就有了product的新值 00:01:12.100 --> 00:01:14.200 我们在很久之前就知道 00:01:14.200 --> 00:01:17.500 在Python里的“for i in range” 00:01:17.500 --> 00:01:19.700 这里的range部分 00:01:19.700 --> 00:01:22.870 这里的range返回一列数 00:01:22.870 --> 00:01:26.100 它返回一列number的元素 00:01:26.100 --> 00:01:29.270 我们之前已经将其传递给number 00:01:29.270 --> 00:01:32.090 那么如果我们假设 我一开始就应该说的 00:01:32.090 --> 00:01:33.910 假设我们正调用- 00:01:33.910 --> 00:01:35.440 为了讲的更详细 00:01:35.440 --> 00:01:45.080 假设这是调用factorial(3)的结果 00:01:45.080 --> 00:01:47.530 那么我们传递给函数factorial的参数是3 00:01:47.530 --> 00:01:51.710 那么变量number就指向3 00:01:51.710 --> 00:01:53.490 当你调用range(number)时 00:01:53.490 --> 00:01:58.450 它就会按照字面意思那样返回一个数列[0,1,2] 00:01:58.450 --> 00:01:59.940 那么三个元素从0开始 00:01:59.940 --> 00:02:03.330 最后一个元素是3减1 也就是2 00:02:03.330 --> 00:02:06.680 那么在这个for循环的每次循环中 00:02:06.680 --> 00:02:09.430 变量i将会被依次赋值成 00:02:09.430 --> 00:02:09.820 数列里的数 00:02:09.820 --> 00:02:12.580 那么在for循环的第一次循环中 00:02:12.580 --> 00:02:14.680 i将会被赋值成0 00:02:14.680 --> 00:02:17.890 那么我们的i就将要指向0 00:02:17.890 --> 00:02:21.880 然后product乘以(i+1) 00:02:21.880 --> 00:02:24.490 好吧 在第一次循环时 00:02:24.490 --> 00:02:27.980 product在进入for循环之前就出现了 它被定义为1 00:02:27.980 --> 00:02:32.240 那么product就是1 而这个表达式就是1乘以- 00:02:32.240 --> 00:02:35.760 我不想用这个颜色来做 00:02:35.760 --> 00:02:36.710 我用- 00:02:36.710 --> 00:02:38.900 我用绛红色把它写出来- 00:02:38.900 --> 00:02:47.370 1乘以i-- i是0 1乘以(0+1) 00:02:47.370 --> 00:02:51.700 加1 然后我们新的product的值就是 00:02:51.700 --> 00:02:53.030 将这个表达式计算出来的值 00:02:53.030 --> 00:02:53.880 就在这里 00:02:53.880 --> 00:02:56.450 product等于这堆东西 00:02:56.450 --> 00:02:59.160 那么我们新的值就是1乘以0加1 00:02:59.160 --> 00:03:01.530 就是1乘以1 也就是1 00:03:01.530 --> 00:03:05.130 这就是在循环语句内的所有东西了 00:03:05.130 --> 00:03:06.040 因为这就是在for循环里 00:03:06.040 --> 00:03:08.340 要完成的全部事情了 00:03:08.340 --> 00:03:11.630 然后我们回到上面去 00:03:11.630 --> 00:03:14.190 我们将会进行 00:03:14.190 --> 00:03:15.960 在for循环里的下一次迭代了 00:03:15.960 --> 00:03:19.470 我猜你们会说 现在i将被赋值成1了 00:03:19.470 --> 00:03:22.420 那么现在i等于1 00:03:22.420 --> 00:03:23.870 这里的这个表达式 00:03:23.870 --> 00:03:25.730 我们取product的旧值 00:03:25.730 --> 00:03:30.040 那么product还是1 所以product是1 00:03:30.040 --> 00:03:39.990 它要乘以i i现在是1了 1再加上1 00:03:39.990 --> 00:03:41.900 这等于什么呢? 00:03:41.900 --> 00:03:45.510 如果你把这些计算出来 就会得到1乘以2 00:03:45.510 --> 00:03:48.230 所以现在product的新值就是2 00:03:48.230 --> 00:03:49.990 那么在我们的第二次迭代后 00:03:49.990 --> 00:03:53.400 在我们第二次循环完成后 00:03:53.400 --> 00:03:56.960 现在它将会回到for循环的起点 00:03:56.960 --> 00:03:59.700 而i将赋值为数列里的下一个数 00:03:59.700 --> 00:04:02.320 它现在将被赋值成2 00:04:02.320 --> 00:04:06.230 那么现在i是2 而这里的这个东西 我们将会有- 00:04:06.230 --> 00:04:08.510 这个是product- product现在是2 00:04:08.510 --> 00:04:13.520 所以它就是2乘以i… 00:04:13.520 --> 00:04:20.080 而i现在是2 再加上1 那么它就是这样的 00:04:20.080 --> 00:04:23.260 它是2乘以3或者说6 00:04:23.260 --> 00:04:27.160 所以新的product是6 然后继续 我们会说: 00:04:27.160 --> 00:04:30.100 好吧 我们还能把i赋值成这里面的其他数吗? 00:04:30.100 --> 00:04:32.210 不行 我们已经用完了所有的数 所以我们会 00:04:32.210 --> 00:04:35.100 跳出for循环 然后我们返回product 00:04:35.100 --> 00:04:39.890 或者说变量product所指向的东西 00:04:39.890 --> 00:04:41.300 实际上这才是我应该说的东西 00:04:41.300 --> 00:04:44.060 应该返回product所指向的那个值 00:04:44.060 --> 00:04:46.300 那个值是6 00:04:46.300 --> 00:04:49.750 所以当你调用factorial(3) 它将返回6 00:04:49.750 --> 00:04:52.050 所以如果你说factorial- 00:04:52.050 --> 00:04:57.960 如果你要求factorial(3)加上factorial(3) 00:04:57.960 --> 00:05:01.800 那就要计算这个表达式 00:05:01.800 --> 00:05:05.370 这个表达式算出来是6 00:05:05.370 --> 00:05:08.330 而这里这个表达式算出的值也是6 00:05:08.330 --> 00:05:09.960 因为这就是函数返回的值 00:05:09.960 --> 00:05:13.860 然后如果你把它们加起来的话 就是12 00:05:13.860 --> 00:05:15.700 所以这就是我们为什么叫它迭代 00:05:15.700 --> 00:05:19.760 我们一直通过相同的一套指令来进行迭代 00:05:19.760 --> 00:05:22.310 现在让我们来比较一下递归的定义 00:05:22.310 --> 00:05:24.550 它在很多方面都更加有趣 00:05:24.550 --> 00:05:27.600 又一次 我们将调用factorial(3) 00:05:27.600 --> 00:05:30.080 factorial(3) 00:05:30.080 --> 00:05:32.240 所以3就是我们的参数 00:05:32.240 --> 00:05:34.240 而这就是number所指向的值 00:05:34.240 --> 00:05:36.650 然后判断number是否小于等于1 00:05:36.650 --> 00:05:38.700 好吧 3不小于等于1 00:05:38.700 --> 00:05:40.220 所以我们不会运行这部分的语句 00:05:40.220 --> 00:05:41.630 我们将会来到else语句 00:05:41.630 --> 00:05:44.140 那么我们将会返回number- 00:05:44.140 --> 00:05:48.850 我们要返回number乘以这个的阶乘 00:05:48.850 --> 00:05:55.540 所以它的值就会是number- number是3- 00:05:55.540 --> 00:05:57.180 那是我们传递的参数 00:05:57.180 --> 00:06:07.620 乘上number减1的阶乘 00:06:07.620 --> 00:06:10.890 而number减1的值是2 3减1等于2 00:06:10.890 --> 00:06:12.370 所以就是factorial(2) 00:06:12.370 --> 00:06:14.760 好吧 那是另一个调用factorial的函数 00:06:14.760 --> 00:06:15.490 所以我们返回去 00:06:15.490 --> 00:06:18.740 还是factorial函数 只是参数现在是2 所以number是2 00:06:18.740 --> 00:06:21.540 我们继续 如果number小于等于1 我们执行这条语句 00:06:21.540 --> 00:06:22.960 但是number没有小于等于1 00:06:22.960 --> 00:06:24.720 它是2 所以我们转到else部分 00:06:24.720 --> 00:06:28.200 那么我们现在想要返回的是 00:06:28.200 --> 00:06:30.040 number乘上factorial(number-1) 00:06:30.040 --> 00:06:31.490 那么在这个情况下… 00:06:31.490 --> 00:06:34.540 在这个情况下 number现在是2 00:06:34.540 --> 00:06:37.820 而现在我们要将它乘上 00:06:37.820 --> 00:06:43.660 乘上factorial(2-1) 00:06:43.660 --> 00:06:45.210 好吧 2减1就是1 00:06:45.210 --> 00:06:46.890 乘以factorial(1) 00:06:46.890 --> 00:06:48.550 好吧 我们又做了一个函数调用 00:06:48.550 --> 00:06:51.600 那么解释器不得不记住 00:06:51.600 --> 00:06:53.090 我们做的这一系列的函数调用 00:06:53.090 --> 00:06:55.620 并不得不一直向更深处挖掘 00:06:55.620 --> 00:06:57.520 那么现在 我们调用了factorial(1) 00:06:57.520 --> 00:07:00.660 factorial(1) 1是参数 00:07:00.660 --> 00:07:01.910 number现在指向1 00:07:01.910 --> 00:07:03.810 如果number小于等于1 00:07:03.810 --> 00:07:05.400 number确实小于等于1 00:07:05.400 --> 00:07:06.660 现在这就是我们所称的基本情况 00:07:06.660 --> 00:07:08.040 我们一直在走向它 00:07:08.040 --> 00:07:11.530 那么number小于等于1 返回1 00:07:11.530 --> 00:07:13.190 那么在这个情况下 00:07:13.190 --> 00:07:16.420 当我们调用factorial(1) 它就会返回1 00:07:16.420 --> 00:07:17.720 所以我们现在知道了 00:07:17.720 --> 00:07:22.910 factorial(2)等于2乘以1 00:07:22.910 --> 00:07:26.410 那么这就等于2 00:07:26.410 --> 00:07:29.440 我们知道factorial(3)等于3乘以2 00:07:29.440 --> 00:07:35.840 也就是6 00:07:35.840 --> 00:07:38.030 所以 非常不一样的思考方式 00:07:38.030 --> 00:07:39.540 却得到了完全一样的结果 00:07:39.540 --> 00:07:42.140 又一次 如果你计算factorial(3)加上factorial(3) 00:07:42.140 --> 00:07:44.080 你用哪种方式来完成它并没关系 00:07:44.080 --> 00:07:46.530 我们会得到6加6或者说12