首先来认识一下递归
递归
是指在函数自身内部调用自己,好理解,自己调用自己嘛,然后它包含两个方面,一种是递归条件,一种是基准条件
基准条件
这是递归的终止条件,当满足基准条件时,函数不再调用自身,从而避免无限循环(就是一个限制循环的终点线)
递归条件
这是函数调用自身的部分,用来逐步解决问题。(这是递归运行的发动机)
例子
阶乘(factorial)是递归的经典示例。阶乘函数的定义是:
n! = n × (n-1)!
(递归条件)
0! = 1
(基准条件)
def factorial(n):
if n == 0:
return 1 # 基准条件
else:
return n * factorial(n - 1) # 递归条件
解释:
基准条件:当 n
等于 0
时,函数返回 1
,这是递归的终止条件
递归条件:函数计算 n!
时调用 factorial(n - 1)
来计算 (n-1)!
。这个调用会继续进行,直到达到基准条件
斐波那契数列
斐波那契数列的定义是:
F(n) = F(n-1) + F(n-2)
(递归条件)
F(0) = 0
和 F(1) = 1
(基准条件)
def fibonacci(n):
if n == 0:
return 0 # 基准条件
elif n == 1:
return 1 # 基准条件
else:
return fibonacci(n - 1) + fibonacci(n - 2) # 递归条件
解释:
基准条件:当 n
等于 0
或 1
时,返回相应的值。
递归条件:函数计算 F(n)
时调用 fibonacci(n - 1)
和 fibonacci(n - 2)
,将问题拆解为更小的子问题。
递归的优缺点
优点:代码简洁:递归可以使代码更简洁、更具表达力,特别是在处理复杂数据结构如树和图时。
缺点:性能问题:递归可能导致大量的函数调用,特别是在处理大量数据时,这可能导致性能下降或者栈溢出。可读性:对于复杂的递归,可能会使代码难以理解。
这些东西都还好理解,那么接下来来介绍一下分治思想
分治思想
分治思想就是把问题拆分为几个小问题,把这些小问题解决的解合并得到原来问题的解。
基本步骤
分解:将原始问题分解成若干个规模较小的子问题。通常,子问题是原问题的一个子集或缩小版。
解决:递归地解决这些子问题。如果子问题足够小,直接解决它们;否则,继续应用分治策略。
合并:将子问题的解合并成原始问题的解。
经典示例
下面介绍两种算法
1. 归并排序(Merge Sort)
其核心思想是利用分治策略将一个大数组分解成多个小数组,排序这些小数组,然后将它们合并成一个有序的大数组。(大数组分成小数组,再合并成大数组)
过程:分解:将数组递归地分割成两半,直到每个子数组只有一个元素(已排序)(大数组分成小数组)
合并:将这些小数组合并成一个有序的大数组。合并操作涉及将两个已排序的子数组合并成一个更大的排序数组。(小数组合并成大数组)
python展示
def merge_sort(arr):
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left_half = merge_sort(arr[:mid])
right_half = merge_sort(arr[mid:])
return merge(left_half, right_half)
def merge(left, right):
sorted_arr = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] < right[j]:
sorted_arr.append(left[i])
i += 1
else:
sorted_arr.append(right[j])
j += 1
sorted_arr.extend(left[i:])
sorted_arr.extend(right[j:])
return sorted_arr
分解:merge_sort
函数将数组分成两半,然后递归地对每一半进行排序。
合并:merge
函数将两个已排序的子数组合并成一个排序好的数组。
2. 快速排序(Quick Sort)
其核心思想是选择一个“基准”元素,然后将数组分成两个或者三个子数组,一个包含比基准小的元素,另一个包含比基准大的元素,然后递归地对两个子数组进行排序。(简单来说就是给个标准,然后把整个数组分成两部分,一个比标准高,一个比标准低,或者一个等于标准,然后通过递归排序)
过程:
分解:选择一个基准元素,将数组分成两个部分:小于基准的元素和大于基准的元素。
解决:递归地对两个子数组进行排序。
合并:快速排序不需要显式的合并步骤,因为它在原地进行排序。
def quick_sort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quick_sort(left) + middle + quick_sort(right)
分解:选择基准元素并将数组分成三个部分(小于、等于、大于基准)
解决:递归地对这三个部分进行排序。
合并:通过拼接已排序的部分得到最终结果。
以上提到的两种排序算法后续也会慢慢介绍。