#include<iostream>
using namespace std;
void foo(int a, int b, int c)
{
if(a > b)
foo(c, a, b);
else
cout<<a<<','<<b<<','<<c<<endl;
}
int main()
{
int a, b, c;
cin >> a >> b >> c;
foo(a, b, c);
return 0;
}输入:2 1 3 输出:__________
这题考递归调用与参数轮换,拿到题先别急着写代码,把主调的(a,b,c)代入foo,看a>b不成立吗?代入后新参数是(c,a,b),再判断,直到a≤b输出。
学生最容易把递归里的参数顺序记反,写成foo(b,c,a)或foo(a,c,b),那样不仅逻辑不对,递归深度也会乱;还有人只看了第一层递归就以为结束了,忘了递归是层层嵌套的,必须把每一层的参数都写出来才能看到最终输出;另外把条件判断看错成a>b时才输出,其实a≤b才输出。
这道题考查的是递归函数中参数传递的顺序,以及递归终止条件的判断。
题目给出的代码是一个典型的递归函数foo,它接收三个整型参数a、b、c。函数的逻辑非常简单:如果a大于b,就递归调用自己,但这次传入的参数不是原来的a、b、c,而是进行了轮换——新的参数变成(c, a, b);如果a不大于b,则直接输出当前的a、b、c,并以换行符结束。这个else分支就是递归的终止条件。
命题人挖坑的视角:这类题在NOIP初赛和GESP考试中非常常见,命题人喜欢考的就是“递归调用的参数变化”。很多学生看到foo(c, a, b)会下意识地觉得“这是把a和c换一下”,或者“这是把b和c换一下”,但真正要理解的是:新函数的第一个参数是旧函数的第三个参数,第二个参数是旧函数的第一个参数,第三个参数是旧函数的第二个参数。这种轮换如果记错,整个递归过程就会完全跑偏。
拿到题怎么想? 1. 先看main函数,它读入三个整数a、b、c,然后调用foo(a, b, c)。输入是2 1 3,所以第一次调用是foo(2, 1, 3)。 2. 进入foo,检查条件a > b。此时a=2,b=1,显然2 > 1成立,所以执行foo(c, a, b),也就是foo(3, 2, 1)。 3. 进入第二层递归,a=3,b=2,3 > 2仍然成立,继续执行foo(c, a, b),也就是foo(1, 3, 2)。 4. 进入第三层递归,a=1,b=3,1 > 3不成立,于是执行else分支,输出1,3,2,然后函数返回。 5. 因为第三层是终止条件,不会再继续递归,所以程序结束。
逐层推演(可以用纸笔模拟):
(2, 1, 3),2>1,递归调用foo(3, 2, 1)。(3, 2, 1),3>2,递归调用foo(1, 3, 2)。(1, 3, 2),1≤3,输出1,3,2。易错点提醒:
foo(b, c, a)或foo(a, c, b),那样会导致无限递归或输出错误。a > b时才输出,其实a ≤ b才输出。考频与趋势:
从数据看,“递归函数”和“函数与递归”在近年考频明显上升,尤其是2023-2025年,GESP四级、五级、六级以及NOIP提高组初赛都频繁出现。2026年数据中,“分支结构”在NOIP提高组初赛考了100题(可能是模拟题或预测数据),而“递归函数”在2026年考了18题,说明递归类题目在提高组初赛仍占重要地位。
预测:基于现有数据,未来考试仍会高频出现递归函数的参数轮换、终止条件判断等题型,尤其是GESP四级、五级、六级和NOIP提高组初赛。题目形式可能更复杂,比如多层嵌套递归、带返回值递归,或者结合数组、指针等数据结构。暂无足够依据预测具体年份的考频变化,但趋势是递归类题目不会减少,反而可能因为算法难度提升而更受命题人青睐。