Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting a recursive implementation to a loop based implementation

Tags:

java

closures

I have two interfaces which is responsible for holding a closure

Here is the first one for holding the closure when it comes to a map operation.

package com.fs;

/**
 * This interface is responsible for holding the closures when it comes to map.
 * It uses two generic types. One for the argument and one for the return type.
 * @param <B> Generic type 
 * @param <A> Generic type
 */
public interface Func<B,A> {
    /**
     * Function prototype m takes an argument of type A and returns a type B.
     * A map operation can produce a different type.
     * @param x of type A
     * @return type B
     */
     B m(A x); 
}

And the second one for filtering operations

package com.fs;


/**
 * This interface is responsible for holding the closures when it comes to filter.
 * @param <A> Generic type 
 */
public interface Pred<A> {
    /**
     * Function prototype m takes an argument of type A and returns a boolean.
     * A filter operation checks every element if it fits a predicate.
     * @param x of type A
     * @return boolean
     */
    boolean m(A x);
}

I have a class named CList which is capable of working with closures.

package com.impl.list;

import com.fs.*;

public class CList<T> {
    T head;
    CList<T> tail;

    public CList(T x, CList<T> xs){
        head = x;
        tail = xs;
    }

    static <A,B> CList<B> map(Func<B,A> f, CList<A> xs){
        if(xs==null){
            return null;
        }
        return new CList<>(f.m(xs.head),map(f,xs.tail));
    }

    static <A,B> CList<B> maploop(Func<B,A> f, CList<A> xs){
        //?????
        return null;
    }

    static <A> CList<A> filter(Pred<A> f, CList<A> xs){
        if(xs == null){
            return null;
        }
        if(f.m(xs.head)){
            return new CList<>(xs.head, filter(f,xs.tail));
        }
        return filter(f,xs.tail);
    }

    static <A> int length(CList<A> xs){
        int ans =0;
        while(xs!= null){
            ++ans;
            xs=xs.tail;
        }
        return ans;
    }
}

Here is my public interface implementing CList with closures.

package com.impl.list;

import com.fs.Func;
import com.fs.Pred;

public class CListClient {
    public static CList<Integer> doubleAll(CList<Integer> xs){
        Func<Integer, Integer> df = new Func<Integer, Integer>() {
            @Override
            public Integer m(Integer x) {
                return x * 2;
            }
        };

        return CList.map(df, xs);
    }

    public static int countNs(CList<Integer> xs,final int n){
        Pred<Integer> pf = new Pred<Integer>() {
            @Override
            public boolean m(Integer x) {
                return x==n;
            }
        };
        return CList.length(CList.filter(pf, xs));
    }

    public static CList<Integer> doubleAllloop(CList<Integer> xs){
        Func<Integer, Integer> df = new Func<Integer, Integer>() {
            @Override
            public Integer m(Integer x) {
                return x * 2;
            }
        };

        return CList.maploop(df, xs);
    }
}

And a simple tester:

package basic;


import com.impl.list.CList;
import com.impl.list.CListClient;
import org.junit.Test;


public class ListTester {

    CList<Integer> intlist_1 = new CList<>(new Integer(1),null);
    CList<Integer> intlist_2 = new CList<>(new Integer(2),intlist_1);
    CList<Integer> intlist_3 = new CList<>(new Integer(3),intlist_2);
    CList<Integer> intlist_4 = new CList<>(new Integer(4),intlist_3);
    CList<Integer> intlist_5 = new CList<>(new Integer(4),intlist_4);
    CList<Integer> intlist = new CList<>(new Integer(5),intlist_5);

    @Test
    public void test_doubleAll(){
        CList<Integer> doubled = CListClient.doubleAll(intlist);
        CList<Integer> doubledloop = CListClient.doubleAllloop(intlist);

    }

    @Test
    public void test_CountNs(){
        int count3s = CListClient.countNs(intlist, 3);
    }
}

I am trying to convert the map function which is implemented in a recursive way to a while loop. I named it maploop. It hurts my brain for two days.Any hint will make me very happy.I am asking this question here since there is probability that someone may take Dan Grossman course and see the example and try to implement that function. I prefer a hint than an actual answer. Thanks.

like image 282
cgon Avatar asked Apr 05 '13 15:04

cgon


People also ask

How do you convert a recursive to a loop?

Initialize the accumulator before the while-loop. Use the negation of the base-case condition as the loop's condition. Use the recursive function's body (except the recursive call) as the body of the while-loop. After the loop, apply the base-case update of the accumulator and return its value.

Can all recursive problems be converted to loops?

So, yes all-recursive code can be converted to iteration.

Which is used to convert from recursive to iterative implementation of an algorithm?

Which data structure is best suited for converting recursive implementation to iterative implementation of an algorithm? Explanation: Since function calls are executed in Last In First Out order, stack is the data structure for converting recursive to iterative implementation.

Can loops replace recursion?

Any recursive algorithm can be rewritten to use loops instead. The opposite is also true. Any iterative algorithm can be written in terms of recursion only. expressiveness: some algorithms are just naturally simpler or easier to write with loops.


1 Answers

When converting a recursive function to an iterative function, you have to examine which non tail call state is required, if any. Then create a stack and push the states onto the stack, and code it like you would the recursive function otherwise. If you have multiple recursive calls in the function, you'll need your new state item to also contain a value indicating at which point in the function you are.

In this case, you only have one recursive call, and the only state is xs, so things are pretty simple and you don't need a custom state object.

Here's how I'd do things (not tested).

static <A,B> CList<B> maploop(Func<B,A> f, CList<A> xs){
    Stack<CList<A>> stack = new Stack<>();

    while(xs != null){
        stack.push(xs);
        xs = xs.tail;
    }

    CList<a> result = xs;

    while(!stack.empty()){
        xs = stack.pop();
        result = new CList<>(f.m(xs.head), result);
    }

    return result;
}    
like image 69
Antimony Avatar answered Sep 22 '22 03:09

Antimony