国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

ホームページ ウェブフロントエンド jsチュートリアル スタックを使用した再帰から反復(fù)への変換: 実踐ガイド

スタックを使用した再帰から反復(fù)への変換: 実踐ガイド

Dec 22, 2024 pm 06:45 PM

Converting Recursion to Iteration Using a Stack: A Practical Guide

再帰はコンピュータ サイエンスにおける強(qiáng)力な手法であり、ツリー トラバーサル、深さ優(yōu)先検索、バックトラッキング アルゴリズムなどのタスクによく使用されます。ただし、再帰は関數(shù)呼び出しのオーバーヘッドと呼び出しスタックの維持により、時(shí)間とスペースの両方の點(diǎn)で効率が低下する可能性があります。場(chǎng)合によっては、明示的なスタックを使用して再帰呼び出しをシミュレートする反復(fù)アプローチに再帰を変換すると有益です。この記事では、JavaScript のスタックを使用して再帰的アルゴリズムを反復(fù)的アルゴリズムに変換するためのステップバイステップのガイドを提供します。


再帰を反復(fù)に変換する理由

再帰を反復(fù)に変換する理由はいくつかあります。

  1. スタック オーバーフロー: 深い再帰呼び出しにより呼び出しスタックが枯渇し、スタック オーバーフローが発生する可能性があります。明示的なスタックを使用すると、この問(wèn)題を回避できます。
  2. 効率: 反復(fù)ソリューションは、呼び出しスタックを維持するオーバーヘッドを必要としないため、一般にメモリ効率が高くなります。
  3. より良い制御: 明示的なスタックを使用すると、特にバックトラッキングが関係する場(chǎng)合に、アルゴリズムの実行をより詳細(xì)に制御できます。

スタックを使用して再帰を反復(fù)に変換するためのテンプレート

スタックを使用して再帰関數(shù)を反復(fù)関數(shù)に変換する場(chǎng)合、一般的なアプローチは、さまざまな種類(lèi)のアルゴリズム (ツリー トラバーサル、バックトラッキング問(wèn)題、グラフ トラバーサルなど) 間でも同様です。以下は、さまざまなシナリオに適応できる柔軟なテンプレートです。


一般的なテンプレート

1. 再帰関數(shù)(例)

function recursiveFunction(args) {
    // Base case
    if (baseCondition) {
        // Handle the base case
        return;
    }

    // Recursive calls
    for (let i = 0; i < someLimit; i++) {
        recursiveFunction(newArgs);
    }
}

2. スタックを使用した反復(fù)関數(shù)

上記の再帰関數(shù)を反復(fù)関數(shù)に変換するには、次の手順に従います。

function iterativeFunction(args) {
    // Initialize the stack
    let stack = [initialState];

    // Loop until the stack is empty
    while (stack.length > 0) {
        // Pop the current state from the stack
        let currentState = stack.pop();

        // Handle the base case (optional, since we can check on each iteration)
        if (baseCondition) {
            continue;  // Skip or handle the base case
        }

        // Process the current state
        processState(currentState);

        // Push next states onto the stack
        for (let i = 0; i < someLimit; i++) {
            let newState = generateNewState(currentState, i);
            stack.push(newState);
        }
    }
}

テンプレートの內(nèi)訳

  1. スタックを初期化します:

    スタックは開(kāi)始狀態(tài)で初期化される必要があります。これは、最初の引數(shù)またはトラバーサルの最初のノードである可能性があります。

  2. スタックをループします:

    ループは、元の関數(shù)で行われた再帰呼び出しを表す項(xiàng)目がスタックにある限り継続します。

  3. 基本條件の処理:

    再帰では、基本條件によってさらなる再帰が必要かどうかがチェックされます。反復(fù)アプローチでは、ループ內(nèi)で同じチェックを?qū)g行できます?;緱l件が満たされた場(chǎng)合は、 continue を使用して以降の処理をスキップできます。

  4. 現(xiàn)在の狀態(tài)を処理します:

    現(xiàn)在の反復(fù)の狀態(tài)を処理します (現(xiàn)在の再帰呼び出しで発生する処理と同等)。

  5. 次の狀態(tài)をプッシュ:

    再帰関數(shù)が新しい再帰関數(shù)を呼び出すのと同じように、ここでは次の狀態(tài) (つまり、処理される関數(shù)の引數(shù)またはノード) をスタックにプッシュします。


変換例: 順序ツリー走査

再帰的バージョン:

function recursiveFunction(args) {
    // Base case
    if (baseCondition) {
        // Handle the base case
        return;
    }

    // Recursive calls
    for (let i = 0; i < someLimit; i++) {
        recursiveFunction(newArgs);
    }
}

スタックを使用した反復(fù)バージョン:

function iterativeFunction(args) {
    // Initialize the stack
    let stack = [initialState];

    // Loop until the stack is empty
    while (stack.length > 0) {
        // Pop the current state from the stack
        let currentState = stack.pop();

        // Handle the base case (optional, since we can check on each iteration)
        if (baseCondition) {
            continue;  // Skip or handle the base case
        }

        // Process the current state
        processState(currentState);

        // Push next states onto the stack
        for (let i = 0; i < someLimit; i++) {
            let newState = generateNewState(currentState, i);
            stack.push(newState);
        }
    }
}

再帰を反復(fù)に変換する例

例 1: グラフ上の深さ優(yōu)先検索 (DFS)

深さ優(yōu)先検索 (DFS) は通常、再帰を使用して実裝されます。再帰的 DFS アルゴリズムは次のとおりです:

function inorderTraversal(root) {
    if (root === null) return;
    inorderTraversal(root.left);
    console.log(root.value);
    inorderTraversal(root.right);
}

スタックを使用した反復(fù)バージョン:

function inorderTraversalIterative(root) {
    let stack = [];
    let current = root;

    while (stack.length > 0 || current !== null) {
        // Reach the leftmost node
        while (current !== null) {
            stack.push(current);
            current = current.left;
        }

        // Visit the node
        current = stack.pop();
        console.log(current.value);

        // Move to the right node
        current = current.right;
    }
}

この例では、スタックは訪問(wèn)するノードを明示的に保持し、ループを使用して再帰呼び出しをシミュレートします。


例 2: 順序どおりのツリー走査 (反復(fù))

バイナリ ツリーの順序どおりの走査は通常、再帰的に行われます。再帰バージョンは次のとおりです:

function dfs(graph, node, visited = new Set()) {
    if (visited.has(node)) return;
    console.log(node);
    visited.add(node);

    for (let neighbor of graph[node]) {
        dfs(graph, neighbor, visited);
    }
}

スタックを使用した反復(fù)バージョン:

function dfsIterative(graph, startNode) {
    let stack = [startNode];
    let visited = new Set();

    while (stack.length > 0) {
        let node = stack.pop();

        if (visited.has(node)) continue;

        console.log(node);
        visited.add(node);

        // Add neighbors to the stack in reverse order to maintain DFS order
        for (let neighbor of graph[node].reverse()) {
            if (!visited.has(neighbor)) {
                stack.push(neighbor);
            }
        }
    }
}

この場(chǎng)合、スタックは訪問(wèn)するノードの追跡に役立ち、內(nèi)部ループは左端のノードに到達(dá)するまでツリーの左側(cè)を下に移動(dòng)します。


例 3: サブセットの生成 (バックトラッキング)

セットのサブセットを生成するためのバックトラッキング アプローチは、次のように再帰的に実裝できます。

function inorderTraversal(root) {
    if (root === null) return;
    inorderTraversal(root.left);
    console.log(root.value);
    inorderTraversal(root.right);
}

スタックを使用した反復(fù)バージョン:

function inorderTraversalIterative(root) {
    let stack = [];
    let current = root;

    while (stack.length > 0 || current !== null) {
        // Reach the leftmost node
        while (current !== null) {
            stack.push(current);
            current = current.left;
        }

        // Visit the node
        current = stack.pop();
        console.log(current.value);

        // Move to the right node
        current = current.right;
    }
}

反復(fù)バージョンでは、スタックを使用して再帰的な関數(shù)呼び出しをシミュレートします。 currentSubset はインプレースで変更され、スタックは新しい狀態(tài)をプッシュすることでバックトラックを処理します。


例 4: 順列の生成

セットのすべての順列を生成するには、通常、再帰が使用されます。

function subsets(nums) {
    let result = [];
    function backtrack(start, currentSubset) {
        result.push([...currentSubset]);
        for (let i = start; i < nums.length; i++) {
            currentSubset.push(nums[i]);
            backtrack(i + 1, currentSubset);
            currentSubset.pop();
        }
    }
    backtrack(0, []);
    return result;
}

スタックを使用した反復(fù)バージョン:

function subsetsIterative(nums) {
    let stack = [{start: 0, currentSubset: []}];
    let result = [];

    while (stack.length > 0) {
        let { start, currentSubset } = stack.pop();
        result.push([...currentSubset]);

        // Explore subsets by including elements from `start` onwards
        for (let i = start; i < nums.length; i++) {
            currentSubset.push(nums[i]);
            stack.push({ start: i + 1, currentSubset: [...currentSubset] });
            currentSubset.pop(); // backtrack
        }
    }

    return result;
}

この反復(fù)バージョンでは、スタックを使用して順列の現(xiàn)在の狀態(tài)を保存します。バックトラッキングは、スタックから狀態(tài)をプッシュおよびポップすることによって処理されます。


例 5: N-Queens 問(wèn)題 (バックトラッキング)

N-Queens 問(wèn)題は、多くの場(chǎng)合、再帰的バックトラッキングを使用して解決されます。

function permute(nums) {
    let result = [];
    function backtrack(start) {
        if (start === nums.length) {
            result.push([...nums]);
            return;
        }
        for (let i = start; i < nums.length; i++) {
            [nums[start], nums[i]] = [nums[i], nums[start]];  // swap
            backtrack(start + 1);
            [nums[start], nums[i]] = [nums[i], nums[start]];  // backtrack (swap back)
        }
    }
    backtrack(0);
    return result;
}

スタックを使用した反復(fù)バージョン:

function recursiveFunction(args) {
    // Base case
    if (baseCondition) {
        // Handle the base case
        return;
    }

    // Recursive calls
    for (let i = 0; i < someLimit; i++) {
        recursiveFunction(newArgs);
    }
}

結(jié)論

スタックを使用して再帰を反復(fù)に変換することは、多くのアルゴリズム、特にバックトラッキングやツリー/グラフの走査を伴うアルゴリズムにとって貴重な手法です。明示的なスタックを使用することで、深い再帰を回避し、関數(shù)の狀態(tài)を手動(dòng)で管理し、アルゴリズムの実行をより適切に制御できるようになります。これらの例は、獨(dú)自のコードで同様の問(wèn)題に取り組む際のガイドとして役立ちます。

以上がスタックを使用した再帰から反復(fù)への変換: 実踐ガイドの詳細(xì)內(nèi)容です。詳細(xì)については、PHP 中國(guó)語(yǔ) Web サイトの他の関連記事を參照してください。

このウェブサイトの聲明
この記事の內(nèi)容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰屬します。このサイトは、それに相當(dāng)する法的責(zé)任を負(fù)いません。盜作または侵害の疑いのあるコンテンツを見(jiàn)つけた場(chǎng)合は、admin@php.cn までご連絡(luò)ください。

ホットAIツール

Undress AI Tool

Undress AI Tool

脫衣畫(huà)像を無(wú)料で

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード寫(xiě)真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

寫(xiě)真から衣服を削除するオンライン AI ツール。

Clothoff.io

Clothoff.io

AI衣類(lèi)リムーバー

Video Face Swap

Video Face Swap

完全無(wú)料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡(jiǎn)単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無(wú)料のコードエディター

SublimeText3 中國(guó)語(yǔ)版

SublimeText3 中國(guó)語(yǔ)版

中國(guó)語(yǔ)版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強(qiáng)力な PHP 統(tǒng)合開(kāi)発環(huán)境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開(kāi)発ツール

SublimeText3 Mac版

SublimeText3 Mac版

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

Java vs. JavaScript:混亂を解消します Java vs. JavaScript:混亂を解消します Jun 20, 2025 am 12:27 AM

JavaとJavaScriptは異なるプログラミング言語(yǔ)であり、それぞれ異なるアプリケーションシナリオに適しています。 Javaは大規(guī)模なエンタープライズおよびモバイルアプリケーション開(kāi)発に使用されますが、JavaScriptは主にWebページ開(kāi)発に使用されます。

JavaScriptコメント:短い説明 JavaScriptコメント:短い説明 Jun 19, 2025 am 12:40 AM

JavaScriptcommentsEareEssentialential-formaining、およびGuidingCodeexecution.1)single-linecommentseared forquickexplanations.2)多LinecommentsexplaincomplexlogiCorprovidededocumentation.3)clarifyspartsofcode.bestpractic

JSで日付と時(shí)間を操作する方法は? JSで日付と時(shí)間を操作する方法は? Jul 01, 2025 am 01:27 AM

JavaScriptで日付と時(shí)間を処理する場(chǎng)合は、次の點(diǎn)に注意する必要があります。1。日付オブジェクトを作成するには多くの方法があります。 ISO形式の文字列を使用して、互換性を確保することをお?jiǎng)幛幛筏蓼埂?2。時(shí)間情報(bào)を取得および設(shè)定して、メソッドを設(shè)定でき、月は0から始まることに注意してください。 3.手動(dòng)でのフォーマット日付には文字列が必要であり、サードパーティライブラリも使用できます。 4.ルクソンなどのタイムゾーンをサポートするライブラリを使用することをお?jiǎng)幛幛筏蓼?。これらの重要なポイントを?xí)得すると、一般的な間違いを効果的に回避できます。

なぜの下部にタグを配置する必要があるのですか? なぜの下部にタグを配置する必要があるのですか? Jul 02, 2025 am 01:22 AM

PLACSTHETTHETTHE BOTTOMOFABLOGPOSTORWEBPAGESERVESPAGESPORCICALPURPOSESESFORSEO、userexperience、andDesign.1.IthelpswithiobyAllowingseNStoAccessKeysword-relevanttagwithtagwithtagwithtagwithemaincontent.2.iTimrovesexperiencebyepingepintepepinedeeping

JavaScript vs. Java:開(kāi)発者向けの包括的な比較 JavaScript vs. Java:開(kāi)発者向けの包括的な比較 Jun 20, 2025 am 12:21 AM

javascriptispreferredforwebdevelopment、whilejavaisbetterforlge-scalebackendsystemsandroidapps.1)javascriptexcelsininintingtivewebexperiences withitsdynAmicnature anddommanipulation.2)javaofferstruntypyping-dobject-reientedpeatures

JavaScript:効率的なコーディングのためのデータ型の調(diào)査 JavaScript:効率的なコーディングのためのデータ型の調(diào)査 Jun 20, 2025 am 12:46 AM

javascripthassevenfundamentaldatypes:number、string、boolean、undefined、null、object、andsymbol.1)numberseadouble-precisionformat、有用であるため、有用性の高いものであるため、but-for-loating-pointarithmetic.2)ストリングリムムット、使用率が有用であること

DOMでのイベントの泡立ちとキャプチャとは何ですか? DOMでのイベントの泡立ちとキャプチャとは何ですか? Jul 02, 2025 am 01:19 AM

イベントキャプチャとバブルは、DOMのイベント伝播の2つの段階です。キャプチャは最上層からターゲット要素までであり、バブルはターゲット要素から上層までです。 1.イベントキャプチャは、AddEventListenerのUseCaptureパラメーターをTrueに設(shè)定することにより実裝されます。 2。イベントバブルはデフォルトの動(dòng)作であり、UseCaptureはfalseに設(shè)定されているか、省略されます。 3。イベントの伝播を使用して、イベントの伝播を防ぐことができます。 4.イベントバブルは、動(dòng)的なコンテンツ処理効率を改善するためにイベント委任をサポートします。 5.キャプチャを使用して、ロギングやエラー処理など、事前にイベントを傍受できます。これらの2つのフェーズを理解することは、タイミングとJavaScriptがユーザー操作にどのように反応するかを正確に制御するのに役立ちます。

JavaとJavaScriptの違いは何ですか? JavaとJavaScriptの違いは何ですか? Jun 17, 2025 am 09:17 AM

JavaとJavaScriptは、異なるプログラミング言語(yǔ)です。 1.Javaは、エンタープライズアプリケーションや大規(guī)模なシステムに適した、靜的に型付けされ、コンパイルされた言語(yǔ)です。 2。JavaScriptは動(dòng)的なタイプと解釈された言語(yǔ)であり、主にWebインタラクションとフロントエンド開(kāi)発に使用されます。

See all articles