对函数及递归的通俗理解
没有基础的兄弟可能对函数的递归比较难以理解,特别是递归里返回输出的概念理不清,是如何返回的。
下面是课本上的列子,就拿出来,用我的理解来做解释。希望能帮到对这块还没弄懂的兄弟。
function test($n){
echo $n."nbsp";
if($n>0){
test($n-1);//调用函数本身。
}else{
echo "";
}
echo $n."$nbsp";
}
test(3);//调用函数输出。
?>
得到结果是 3 2 1 0 0 1 2 3
大家比较容易理解的是前面输出的3 2 1 0 但对于后面的 0 1 2 3 为什么输出不是很清楚。
要理解这个递归的回归输出先要弄清楚,什么是函数,
官方解释:
函数(function)是一段完成指定任务的已命名代码块。
使用函数的理由中有一条是:
可提高程序的重用性
重用性就是可以重复使用,不多次编写相同代码。 就是将程序中重复编写的代码写成函数,然后在其他多处需要使用时只用调用函数名就可使用,而不用再次重复编写相同代码。
通俗简单点讲,函数就是一段已经写好的代码一把已经造好的枪,然后将它放在了公共仓库里,
不同功能的函数都有自己的名字【function 函数名(){}】,如同不同功能的枪也有自己的名字,如来福枪,狙击枪,手枪等,这些取好名的函数和枪都已经编写好,造好,放在仓库。
然后有谁想使用某个功能的函数时,到这个仓库里喊这个函数的名字【函数名()】,就将函数拿了出来使用,如同警察依据任务的不同要求到仓库里拿不同功能的枪一样。
————这就是函数的定义。
函数的使用:
官方的叫法就是:调用 如 aaa();
通俗的理解就是:那个谁谁谁(叫函数的名字)过来这里,把交给你的代码给我在这个位置写一遍。
我的理解是,就是是替换,函数的调用就是一个占位符,遇到了这个占位符【aaa()】就替换成这个占位符【aaa()】指定的已经写好的函数里的代码。遇到就替换,然后程序继续按先后的顺序往下执行。
具体例子说明:
/*=============装函数(手枪)的仓库=======================*/
function test($n){
echo $n."nbsp";
if($n>0){
test($n-1);//调用函数本身。
}else{
echo "";
}
echo $n."$nbsp";
}
/*=============装函数(手枪)的仓库======================*/
test(3); //调用函数,按我的想的就是遇到了占位符了,要替换名字叫test的那个函数里的代码,(你也可以理解成到仓库里拿叫test的枪装入3发子弹)
于是test(3)第一次遇到变成了
/***********************第一次调用时替换************************/
echo $n."nbsp"; //这个时候$n=3 子弹是三发
if($n>0){ //判断$n为3大于0 , 执行下边的
test($n-1); //再次遇到调用函数,遇到就替换,(子弹打出去一发)
}else{
echo ""; //不执行
}
echo $n."$nbsp"; // 这个时候$n=3,所以输出3
/***********************第一次调用时替换************************/
/***********************第二次调用时替换************************/
echo $n."nbsp"; //这个时候$n=3 子弹是三发
if($n>0){ //判断$n>3 执行下边的
echo $n."nbsp"; //这个时候$n=2 子弹是二发
if($n>0){ //判断$n为2大于0, 执行下边的
test($n-1); //再次遇到调用函数,遇到就替换,(子弹再打出去一发)
}else{
echo ""; //不执行
}
echo $n."$nbsp";//这个时候$n=2,所以输出2
}else{
echo ""; //不执行
}
echo $n."$nbsp"; //这个时候$n=3,所以输出3
/***********************第二次调用时替换************************/
/***********************第三次调用时替换************************/
echo $n."nbsp"; //这个时候$n=3 子弹是三发
if($n>0){ //判断$n>3 执行下边的
echo $n."nbsp"; //这个时候$n=2 子弹是二发
if($n>0){ //判断$n为2大于0, 执行下边的
echo $n."nbsp"; //这个时候$n=1 子弹是一发
if($n>0){ //判断$n为1 大于0, 执行下边的
test($n-1); //再次遇到调用函数,遇到就替换,(子弹打出去一发)
}else{
echo ""; //不执行
}
echo $n."$nbsp"; // 这个时候$n=1,所以输出1
}else{
echo ""; //不执行
}
echo $n."$nbsp";//这个时候$n=2,所以输出2
}else{
echo ""; //不执行
}
echo $n."$nbsp"; //这个时候$n=3,所以输出3
/***********************第三次调用时替换************************/
/***********************第四次调用时替换************************/
echo $n."nbsp"; //这个时候$n=3 子弹是三发
if($n>0){ //判断$n>3 执行下边的
echo $n."nbsp"; //这个时候$n=2 子弹是二发
if($n>0){ //判断$n为2大于0, 执行下边的
echo $n."nbsp"; //这个时候$n=1 子弹是一发
if($n>0){ //判断$n为1 大于0, 执行下边的
echo $n."nbsp"; //这个时候$n=0 子弹是0发
if($n>0){ //判断$n为0等于0 ,不执行下边的
test($n-1); //因为不执行所以就不替换了。
}else{
echo ""; //输出
}
echo $n."$nbsp"; // 这个时候$n=0,所以输出0
}else{
echo ""; //不执行
}
echo $n."$nbsp"; // 这个时候$n=1,所以输出1
}else{
echo ""; //不执行
}
echo $n."$nbsp";//这个时候$n=2,所以输出2
}else{
echo ""; //不执行
}
echo $n."$nbsp"; //这个时候$n=3,所以输出3
/***********************第四次调用时替换************************/
/*##################最终得到只有if判断语句和基础表达式组成的代码###########################*/
test(3);//在最开始的时候只调用一次替换;
//$n=3
echo $n."nbsp";//输出3
if($n>0){
//test(3-1)替成了下面的
echo $n."nbsp";//输出2
if($n>0){
//test(2-1)替成了下面的
echo $n."nbsp";//输出1
if($n>0){
//test(1-1)替成了下面的
echo $n."nbsp";//输出0
if($n>0){//判断执行
//test()没有替换
test($n-1);//不执行 因为不大约0
}else{
echo "";//输出
}
echo $n."$nbsp";//输出0
}else{
echo "";//不执行
}
echo $n."$nbsp";//输出1
}else{
echo "";//不执行
}
echo $n."$nbsp";//输出2
}else{
echo "";////不执行
}
echo $n."$nbsp";//输出3
/*##################最终得到###########################*/
按照最终得到的代码依次输出的结果就是
输出结果就是 3 2 1 0 0 1 2 3
函数和递归的使用,最终就是解析成上面的代码执行的,
这就是我理解的函数,以及递归,用一句话说:“本来江湖上是没有递归的,出现的函数多了,也就有了递归。”
一点简单的理解,希望能帮助没有基础的兄弟理解函数,理解递归,最终形成自己的理解自己的想法和思路

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









Go 言語は、クロージャとリフレクションという 2 つの動的関数作成テクノロジを提供します。クロージャを使用すると、クロージャ スコープ内の変数にアクセスでき、リフレクションでは FuncOf 関数を使用して新しい関数を作成できます。これらのテクノロジーは、HTTP ルーターのカスタマイズ、高度にカスタマイズ可能なシステムの実装、プラグイン可能なコンポーネントの構築に役立ちます。

C++ 関数の名前付けでは、読みやすさを向上させ、エラーを減らし、リファクタリングを容易にするために、パラメーターの順序を考慮することが重要です。一般的なパラメータの順序規則には、アクション-オブジェクト、オブジェクト-アクション、意味論的な意味、および標準ライブラリへの準拠が含まれます。最適な順序は、関数の目的、パラメーターの種類、潜在的な混乱、および言語規約によって異なります。

再帰関数は、文字列処理の問題を解決するためにそれ自体を繰り返し呼び出す手法です。無限再帰を防ぐために終了条件が必要です。再帰は、文字列の反転や回文チェックなどの操作で広く使用されています。

1. SUM 関数は、列またはセルのグループ内の数値を合計するために使用されます (例: =SUM(A1:J10))。 2. AVERAGE 関数は、列またはセルのグループ内の数値の平均を計算するために使用されます (例: =AVERAGE(A1:A10))。 3. COUNT 関数。列またはセルのグループ内の数値またはテキストの数をカウントするために使用されます。例: =COUNT(A1:A10)。 4. IF 関数。指定された条件に基づいて論理的な判断を行い、結果を返すために使用されます。対応する結果。

再帰は、問題を解決するために関数自体を呼び出すことを可能にする強力な手法です。C++ では、再帰関数は、基本ケース (再帰をいつ停止するかを決定する) と再帰呼び出し (問題を分割する) という 2 つの重要な要素で構成されます。より小さなサブ問題)。基本を理解し、階乗計算、フィボナッチ数列、バイナリ ツリー トラバーサルなどの実践的な例を練習することで、再帰的な直感を構築し、自信を持ってコードで使用することができます。

末尾再帰最適化 (TRO) は、特定の再帰呼び出しの効率を向上させます。末尾再帰呼び出しをジャンプ命令に変換し、コンテキスト状態をスタックではなくレジスターに保存することで、余分な呼び出しとスタックへの戻り操作を排除し、アルゴリズムの効率を向上させます。 TRO を使用すると、末尾再帰関数 (階乗計算など) を最適化できます。末尾再帰呼び出しを goto ステートメントに置き換えることで、コンパイラーは goto ジャンプを TRO に変換し、再帰アルゴリズムの実行を最適化します。

再帰は関数がそれ自体を呼び出す手法ですが、スタック オーバーフローや非効率という欠点があります。代替案には、コンパイラがループへの再帰呼び出しを最適化する末尾再帰最適化、再帰の代わりにループとコルーチンを使用する反復、再帰動作をシミュレートする実行の一時停止と再開が含まれます。

再帰的な定義と最適化: 再帰的: 関数は内部的にそれ自体を呼び出し、より小さなサブ問題に分解できる困難な問題を解決します。末尾再帰: この関数は再帰呼び出しを行う前にすべての計算を実行します。これはループに最適化できます。末尾再帰の最適化条件: 再帰呼び出しが最後の操作です。再帰呼び出しパラメータは、元の呼び出しパラメータと同じです。実用的な例: 階乗の計算: 補助関数 Factorial_helper は末尾再帰最適化を実装し、呼び出しスタックを排除し、効率を向上させます。フィボナッチ数の計算: 末尾再帰関数 fibonacci_helper は、最適化を使用してフィボナッチ数を効率的に計算します。
