递归的几种类型

本文详细介绍了递归在几种经典问题中的应用,包括阶乘、斐波那契数列、倒序输出正整数、汉诺塔问题以及排列问题。通过递归思想,解释了如何解决这些数学和逻辑难题,提供了解决方案的递归表达式和部分实现思路。

原文:https://blog.youkuaiyun.com/qq_34039315/article/details/78679029

1、阶乘

递归思想:n! = n * (n-1)! (直接看公式吧)

首先分析数列的递归表达式: 

int f(int n)
{
	if(n<=1) return 1;
	else return n*f(n-1);
}

2、斐波那契数列

斐波那契数列的排列是:0,1,1,2,3,5,8,13,21,34,55,89,144……依次类推下去,你会发现,它后一个数等于前面两个数的和。在这个数列中的数字,就被称为斐波那契数。

递归思想:一个数等于前两个数的和。(这并不是废话,这是执行思路)

首先分析数列的递归表达式: 

 

int f(n)
{
	if(n<=1) return 1;
	else return f(n-1)+f(n-2);
}

3、倒序输出一个正整数

例如给出正整数 n=12345,希望以各位数的逆序形式输出,即输出54321。

递归思想:首先输出这个数的个位数,然后再输出前面数字的个位数,直到之前没数字。

 首先分析数列的递归表达式:

写法一:

#include<iostream>
using namespace std;

void f(int n)
{
	if(n/10==0) cout<<n;
	else
	{
		cout<<n%10;
		f(n/10);			
	}	
}

int main()
{
	f(12345);
	return 0;	
}

写法二: 

#include<iostream>
using namespace std;
void f(int n)
{
	cout<<n%10;
	if(n/10)
	{
		f(n/10);
	}
}

int main()
{
	f(12345);
	return 0;
}

 

 

4、汉诺塔问题

有n个盘子,3个柱子x,y,z。

1、欲将x柱子上的n个盘子,全部移动到z柱子上;
2、大盘子不能压到小盘子上面。

递归思想: 
1. 将x柱子上的n-1个盘子都移到空闲的y柱子上,并且满足上面的所有条件;
2. 将x杆上的第n个盘子移到z柱子上;
3. 剩下问题就是将y柱子上的n-1个盘子移动到z柱子上了。

公式描述有点麻烦,用语言描述下吧: 
1. 以z柱子为中介,将前n-1个盘子从x柱子挪到y柱子上(本身就是一个n-1的汉诺塔问题了!) ;
2. 将第n个圆盘移动到z柱子上; 
3. 以x柱子为中介,将y柱子上的n-1个盘子移到z柱子上(本身就是一个n-1的汉诺塔问题了!)。
 

#include<iostream>
using namespace std;

void hanoi(int n,char x,char y,char z) //从x柱子,借助y柱子,移动到z柱子 
{
	if(n==0) return;
	else
	{
		hanoi(n-1,x,z,y);   //分治思想,将n-1个盘子看作一个整体
		cout<<"将"<<n<<"号盘子,"<<"从"<<x<<"柱子,移动到"<<z<<"柱子"<<endl;
		hanoi(n-1,y,x,z);		
	}		
} 

int main()
{
	hanoi(5,'A','B','C');
	
	return 0;	
} 

参考:https://blog.youkuaiyun.com/qq_41705423/article/details/82025409 

 

5、排列问题

https://blog.youkuaiyun.com/wzy_1988/article/details/8939140

https://blog.youkuaiyun.com/Hackbuteer1/article/details/7462447

输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则输出由字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab和cba。

递归思想: 
假如针对abc的排列,可以分成 (1)、以a开头,加上bc的排列; (2)、以b开头,加上ac的排列; (3)、以c开头,加上ab的排列。

#include<iostream>
using namespace std;

void permutation(int a[],int k,int n) //k:当前欲固定第k号数据;n:一共有n个数据 
{
	if(k==n-1)  //递归结束条件:选取到第n-1号数据(最后一个数据) 
	{
		for(int i=0;i<n;i++)
		{
			cout<<a[i];
		}
		cout<<endl;
	}
	else
	{
		for(int i=k;i<n;i++)  //轮流当第k号元素 
		{
			swap(a[i],a[k]);  //经过这一步,第k号数据固定下来了 
			permutation(a,k+1,n);  //然后处理后面的数据 
			swap(a[i],a[k]);  //保证下一次循环时,依然是最初的次序 
		}		
	}	
} 

int main()
{
	int a[3]={1,2,3};
	permutation(a,0,3);	
	return 0;
} 

【法二】 

算法笔记 P115

#include<iostream>
using namespace std;
const int maxn=11;

int n,P[maxn],hashTable[maxn]={false};

void generateP(int index)
{
	if(index==n+1) //递归结束条件,已经处理完1号~n号元素
	{
		for(int i=1;i<=n;i++) //从1号开始存储元素,一共n个
		{
			cout<<P[i];
		} 
		cout<<endl;
	}
	for(int x=1;x<=n;x++)
	{
		if(hashTable[x]==false) 
		{
			P[index]=x;
			hashTable[x]=true;
			generateP(index+1);
			hashTable[x]=false;
		}
	}
}
int main()
{
	n=3;
	generateP(1);
	return 0;
}

 

<think> 我们正在讨论使用递归实现功能的方法数量。根据递归的基本思想,我们可以从不同的角度来分类递归实现方法。以下是一些常见递归实现方法: 1. **直接递归(Direct Recursion)**: - 函数直接调用自身。 - 例如:计算阶乘的递归函数。 2. **间接递归(Indirect Recursion)**: - 函数A调用函数B,函数B又调用函数A,形成循环调用。 - 例如:函数A调用函数B,函数B再调用函数A。 3. **尾递归(Tail Recursion)**: - 递归调用是函数体中的最后一条语句,且返回值不需要参与其他运算。 - 尾递归可以被编译器优化为循环,以减少栈空间的使用。 - 例如:尾递归形式的阶乘函数。 4. **非尾递归(Non-Tail Recursion)**: - 递归调用返回后还需要进行额外的计算。 - 例如:在递归调用之后进行乘法运算(如阶乘的非尾递归实现)。 5. **多路递归(Multiple Recursion)**: - 函数在一次调用中多次调用自身。 - 例如:斐波那契数列的递归实现(每个函数调用自身两次)。 6. **相互递归(Mutual Recursion)**: - 两个或多个函数相互调用,形成递归。 - 例如:判断奇偶数的两个函数相互调用。 7. **分治递归(Divide and Conquer Recursion)**: - 将问题分解为多个子问题,递归解决子问题,然后合并结果。 - 例如:归并排序、快速排序。 8. **回溯递归(Backtracking Recursion)**: - 通过递归尝试所有可能的选择,并在失败时回溯。 - 例如:八皇后问题、迷宫求解。 9. **生成器递归(Generative Recursion)**: - 在递归过程中生成新的数据结构(如树、图)的节点。 - 例如:二叉树的构建。 以上分类并不是严格互斥的,一个递归函数可能同时属于多个类别。例如,快速排序既是分治递归,也可能使用尾递归(如果优化得当)。 下面我们通过几个示例来说明不同的递归实现方法: ### 1. 直接递归(阶乘计算) ```python def factorial(n): if n == 0: return 1 return n * factorial(n-1) ``` ### 2. 尾递归(阶乘计算,使用累加器) ```python def factorial_tail(n, acc=1): if n == 0: return acc return factorial_tail(n-1, acc*n) ``` ### 3. 多路递归(斐波那契数列) ```python def fibonacci(n): if n <= 1: return n return fibonacci(n-1) + fibonacci(n-2) ``` ### 4. 相互递归(判断奇偶数) ```python def is_even(n): if n == 0: return True return is_odd(n-1) def is_odd(n): if n == 0: return False return is_even(n-1) ``` ### 5. 分治递归(归并排序) ```python def merge_sort(arr): if len(arr) <= 1: return arr mid = len(arr) // 2 left = merge_sort(arr[:mid]) right = merge_sort(arr[mid:]) return merge(left, right) def merge(left, right): # 合并两个有序数组 result = [] i = j = 0 while i < len(left) and j < len(right): if left[i] < right[j]: result.append(left[i]) i += 1 else: result.append(right[j]) j += 1 result.extend(left[i:]) result.extend(right[j:]) return result ``` ### 6. 回溯递归(八皇后问题) ```python def solve_n_queens(n): def backtrack(row, cols, diag1, diag2, board, res): if row == n: res.append(["".join(row) for row in board]) return for col in range(n): d1 = row - col d2 = row + col if col in cols or d1 in diag1 or d2 in diag2: continue board[row][col] = 'Q' cols.add(col) diag1.add(d1) diag2.add(d2) backtrack(row+1, cols, diag1, diag2, board, res) board[row][col] = '.' cols.remove(col) diag1.remove(d1) diag2.remove(d2) res = [] board = [['.']*n for _ in range(n)] backtrack(0, set(), set(), set(), board, res) return res ``` ### 7. 生成器递归(二叉树的构建) ```python class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right def build_tree(preorder, inorder): if not preorder or not inorder: return None root = TreeNode(preorder[0]) idx = inorder.index(preorder[0]) root.left = build_tree(preorder[1:1+idx], inorder[:idx]) root.right = build_tree(preorder[1+idx:], inorder[idx+1:]) return root ``` 以上示例展示了递归在不同场景下的应用。递归的实现方法多种多样,根据问题的性质选择合适的递归策略是关键。 §§相关问题§§ 1. 递归和迭代在性能上有何差异? 2. 如何避免递归中的栈溢出问题? 3. 尾递归优化是如何实现的? </think> ### 递归实现功能的常见方法 在计算机科学中,递归是通过函数自我调用来解决问题的方法。根据实现方式和应用场景,递归主要可分为以下几种类型: #### 1. **直接递归(Direct Recursion)** 函数直接调用自身,是最常见递归形式。 **示例:计算阶乘** ```python def factorial(n): if n <= 1: # 基线条件 return 1 return n * factorial(n-1) # 递归调用 ``` #### 2. **间接递归(Indirect Recursion)** 多个函数相互调用形成递归链。 **示例:奇偶判断** ```python def is_even(n): if n == 0: return True return is_odd(n-1) # 调用其他函数 def is_odd(n): if n == 0: return False return is_even(n-1) # 回调初始函数 ``` #### 3. **尾递归(Tail Recursion)** 递归调用是函数的最后操作,可被优化为迭代以减少栈开销。 **示例:尾递归阶乘** ```python def factorial_tail(n, acc=1): if n <= 1: return acc return factorial_tail(n-1, acc*n) # 递归在尾部 ``` #### 4. **树形递归(Tree Recursion)** 单次调用中多次递归,形成树状调用结构。 **示例:斐波那契数列** ```python def fibonacci(n): if n <= 1: return n return fibonacci(n-1) + fibonacci(n-2) # 两次递归调用 ``` #### 5. **分治递归(Divide and Conquer)** 将问题拆分为子问题递归求解,再合并结果。 **示例:归并排序** ```python def merge_sort(arr): if len(arr) <= 1: return arr mid = len(arr)//2 left = merge_sort(arr[:mid]) # 递归处理左半部 right = merge_sort(arr[mid:]) # 递归处理右半部 return merge(left, right) # 合并结果 ``` #### 6. **回溯递归(Backtracking)** 通过递归尝试所有可能路径,失败时回退。 **示例:八皇后问题** ```python def solve_queens(board, row=0): if row >= len(board): return True # 找到解 for col in range(len(board)): if is_safe(board, row, col): board[row][col] = 1 # 放置皇后 if solve_queens(board, row+1): # 递归下一行 return True board[row][col] = 0 # 回溯撤销 return False ``` #### 7. **生成器递归(Generative Recursion)** 递归生成复杂数据结构(如树、图)。 **示例:构建二叉树** ```python class Node: def __init__(self, val, left=None, right=None): self.val = val self.left = left self.right = right def build_tree(data): if not data: return None root = Node(data[0]) root.left = build_tree(data[1]) # 递归构建左子树 root.right = build_tree(data[2]) # 递归构建右子树 return root ``` --- ### 关键特点对比 | 类型 | 调用方式 | 适用场景 | 空间复杂度 | |--------------|-------------------|------------------------|-----------------| | 直接递归 | 函数直接调用自身 | 线性问题(阶乘、链表) | $O(n)$ | | 树形递归 | 单次多次递归调用 | 组合问题(斐波那契) | $O(2^n)$ | | 分治递归 | 拆分-解决-合并 | 排序、搜索 | $O(\log n)$ | | 回溯递归 | 尝试-回退 | 约束满足问题(迷宫) | $O(n)$ | > 提示:递归的核心是 **基线条件**(终止条件)和 **递归步骤**(问题分解)。设计时需确保每次递归调用都向基线条件靠近[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值