Recursion or Iteration?

2018-12-31 17:03发布

Is there a performance hit if we use loop instead of recursion or vice versa in algorithms where both can serve the same purpose? Eg : Check if given string is palindrome. I have seen many programmers using recursion as a means to show off when a simple iteration algorithm can fit the bill. Does the compiler play a vital role in deciding what to use?

28条回答
永恒的永恒
2楼-- · 2018-12-31 17:52

Recursion has a disadvantage that the algorithm that you write using recursion has O(n) space complexity. While iterative aproach have a space complexity of O(1).This is the advantange of using iteration over recursion. Then why do we use recursion?

See below.

Sometimes it is easier to write an algorithm using recursion while it's slightly tougher to write the same algorithm using iteration.In this case if you opt to follow the iteration approach you would have to handle stack yourself.

查看更多
呛了眼睛熬了心
3楼-- · 2018-12-31 17:53

Recursion? Where do I start, wiki will tell you “it’s the process of repeating items in a self-similar way"

Back in day when I was doing C, C++ recursion was a god send, stuff like "Tail recursion". You'll also find many sorting algorithms use recursion. Quick sort example: http://alienryderflex.com/quicksort/

Recursion is like any other algorithm useful for a specific problem. Perhaps you mightn't find a use straight away or often but there will be problem you’ll be glad it’s available.

查看更多
浪荡孟婆
4楼-- · 2018-12-31 17:53

Using just Chrome 45.0.2454.85 m, recursion seems to be a nice amount faster.

Here is the code:

(function recursionVsForLoop(global) {
    "use strict";

    // Perf test
    function perfTest() {}

    perfTest.prototype.do = function(ns, fn) {
        console.time(ns);
        fn();
        console.timeEnd(ns);
    };

    // Recursion method
    (function recur() {
        var count = 0;
        global.recurFn = function recurFn(fn, cycles) {
            fn();
            count = count + 1;
            if (count !== cycles) recurFn(fn, cycles);
        };
    })();

    // Looped method
    function loopFn(fn, cycles) {
        for (var i = 0; i < cycles; i++) {
            fn();
        }
    }

    // Tests
    var curTest = new perfTest(),
        testsToRun = 100;

    curTest.do('recursion', function() {
        recurFn(function() {
            console.log('a recur run.');
        }, testsToRun);
    });

    curTest.do('loop', function() {
        loopFn(function() {
            console.log('a loop run.');
        }, testsToRun);
    });

})(window);

RESULTS

// 100 runs using standard for loop

100x for loop run. Time to complete: 7.683ms

// 100 runs using functional recursive approach w/ tail recursion

100x recursion run. Time to complete: 4.841ms

In the screenshot below, recursion wins again by a bigger margin when run at 300 cycles per test

Recursion wins again!

查看更多
不流泪的眼
5楼-- · 2018-12-31 17:55

Recursion is more costly in memory, as each recursive call generally requires a memory address to be pushed to the stack - so that later the program could return to that point.

Still, there are many cases in which recursion is a lot more natural and readable than loops - like when working with trees. In these cases I would recommend sticking to recursion.

查看更多
永恒的永恒
6楼-- · 2018-12-31 17:56

In many cases recursion is faster because of caching, which improves performance. For example, here is an iterative version of merge sort using the traditional merge routine. It will run slower than the recursive implementation because of caching improved performances.

Iterative implementation

public static void sort(Comparable[] a)
{
    int N = a.length;
    aux = new Comparable[N];
    for (int sz = 1; sz < N; sz = sz+sz)
        for (int lo = 0; lo < N-sz; lo += sz+sz)
            merge(a, lo, lo+sz-1, Math.min(lo+sz+sz-1, N-1));
}

Recursive implementation

private static void sort(Comparable[] a, Comparable[] aux, int lo, int hi)
{
    if (hi <= lo) return;
    int mid = lo + (hi - lo) / 2;
    sort(a, aux, lo, mid);
    sort(a, aux, mid+1, hi);
    merge(a, aux, lo, mid, hi);
}

PS - this is what was told by Professor Kevin Wayne (Princeton University) on the course on algorithms presented on Coursera.

查看更多
情到深处是孤独
7楼-- · 2018-12-31 17:57

If you're just iterating over a list, then sure, iterate away.

A couple of other answers have mentioned (depth-first) tree traversal. It really is such a great example, because it's a very common thing to do to a very common data structure. Recursion is extremely intuitive for this problem.

Check out the "find" methods here: http://penguin.ewu.edu/cscd300/Topic/BSTintro/index.html

查看更多
登录 后发表回答