Esiste un modo per visualizzare lo stack durante il metodo di ricorsione?

6

Sto cercando di imparare la ricorsione. Ho copiato questo bit di codice dal mio libro e ho aggiunto i display per aiutarmi a rintracciare cosa sta facendo il metodo e quando.

public static void main(String[] args) {


    System.out.println(sum(4));

}//main

public static int sum(int n) {
    int sum;
    System.out.println("n = " + n + "\n");
    if (n == 1)
        sum = 1;
    else
        sum = sum(n - 1) + n;   
    System.out.println("n after function = " + n + "\n");
    System.out.println("sum after function = " + sum + "\n");
    return sum;
}    

Ecco i risultati:

n = 4

n = 3

n = 2

n = 1

n after function = 1

sum after function = 1

n after function = 2

sum after function = 3

n after function = 3

sum after function = 6

n after function = 4

sum after function = 10

10

Mi sto bloccando su ciò che viene archiviato nello stack, o forse su come viene memorizzato.

C'è un modo per mostrare cosa c'è nella pila mentre n è in conto alla rovescia per 1?

Questo è un concetto strano - è come un loop invisibile che memorizza valori in un modo che non capisco.

    
posta MayNotBe 23.12.2012 - 03:17
fonte

4 risposte

8

Non puoi accedere ai contenuti dello stack direttamente dal tuo codice Java, ma se usi un debugger (che è integrato in ogni IDE moderno) ottieni qualcosa di meglio: elencherà la pila di chiamate al metodo e per ogni livello, se lo selezioni, i valori delle variabili locali nello stack.

Ecco un tutorial su come utilizzare il debugger in eclissi .

    
risposta data 23.12.2012 - 03:35
fonte
5

Puoi usare un debugger come eclipse per visualizzare lo stack in qualsiasi momento, ma provare a immaginare la ricorsione come un loop non è il modo migliore per capirlo. Man mano che si va giù nello stack, si interrompono piccoli frammenti del problema, fino a raggiungere il fondo della pila, dove il problema è banale da risolvere. Poi, quando torni indietro, rimetti i pezzi di nuovo insieme.

sum(4)
sum(3) + 4
sum(2) + 3
sum(1) + 2
1

sum(4) è suddiviso in sum(3) + 4 . sum(3) è scomposto in sum(2) + 3 . Alla fine ottieni sum(1) , che ha una risposta banale di 1 (la prima scelta nella tua dichiarazione if ).

Non c'è modo di suddividerlo ulteriormente, quindi si torna indietro allo stack, aggiungendo 2 , 3 e 4 . È una corsa verso il basso e in cima allo stack, una cosa molto diversa da un ciclo, anche se possono eseguire lo stesso calcolo.

    
risposta data 23.12.2012 - 03:56
fonte
1

Puoi accedere allo stack, ma non i valori sullo stack.

public class StackTrace {

    public static void main(String[] args) {
        recurse(10);
    }

    static void recurse(int depth) {
        for (StackTraceElement each: new Exception().getStackTrace()) System.out.println(each);
        if (depth > 0) recurse(depth - 1);
    }

}
    
risposta data 24.12.2012 - 09:13
fonte
1

Ovviamente potremmo anche scrivere un programma che mantenga il proprio stile C, stack, dove spingiamo tutti gli argomenti e i locals e restituiamo i valori nello stack

public class Main {

    public static void main(String[] args) {
        new Main().run();
    }

    int[] stack = new int[100];
    int base = 0;

    public void run() {

        // push arguments on stack
        stack[base] = 4;
        // increase base pointer and call method
        base += 1;
        call();
        // retrieve result
        int result = stack[base];
        // print it
        System.out.println(result);

    }

    public void call() {
        // push locals on stack and increase base, now arg n
        // is at base - 2 and local sum is at base - 1
        stack[base] = 0;
        base += 1;
        // test if n equals 1
        if (stack[base - 2] == 1) {
            // if yes set sum to 1
            stack[base - 1] = 1;
        } else {
            // push new argument on stack
            stack[base] = stack[base - 2] - 1;
            // increase base pointer and call method
            base += 1;
            call();
            // add result to sum
            stack[base - 1] += stack[base];
            // add n to sum
            stack[base - 1] += stack[base - 2];
        }
        // cache return value
        int result = stack[base - 1];
        // decrease base pointer by size of both args and locals
        base -= 2;
        // push result on stack
        stack[base] = result;
    }
}

i programmi usano la convenzione di chiamata che i chiamanti sono responsabili per il push degli argomenti e l'aumento dei puntatori di base, e i ricevitori sono responsabili della reimpostazione del puntatore di base e di lasciare un valore di ritorno nello stack.

Questo è il modo in cui le chiamate al metodo avvengono a livello della macchina.

    
risposta data 24.12.2012 - 10:07
fonte

Leggi altre domande sui tag