2012-11-26 14 views
7

La mia domanda è se ci sono alcuni modi intelligenti per eseguire il debug di complicati algoritmi ricorsivi. Supponiamo che ne abbiamo uno complicato (non un caso semplice quando il contatore di ricorsione è diminuito in ogni 'iterazione annidata').Debug di un algoritmo ricorsivo

Intendo qualcosa di simile a un attraversamento ricorsivo di un grafico quando i loop sono possibili.

Ho bisogno di controllare se non sto ottenendo il ciclo infinito da qualche parte. E farlo usando solo un debugger non dà una risposta certa (perché non sono sicuro che un algoritmo sia in loop infinito o proceda come dovrebbe).

È difficile spiegarlo senza un esempio concreto. Ma quello di cui ho bisogno è ...

'per verificare se i loop infiniti non avvengono in un algoritmo ricorsivo, per esempio'.

+0

Eseguire il debug utilizzando le istruzioni di stampa? – Minion91

+0

Ho provato. Ma rallenta l'esecuzione (molto) quindi dopo pochi minuti non so se l'algoritmo è ancora in elaborazione (come dovrebbe) o semplicemente è già in loop infinito. 'Lo spazio degli oggetti' per l'iterazione ricorsiva è 'enorme' e la logica nidificata decrescente non è semplice (non ogni iterazione la diminuisce di uno). In casi semplici l'algoritmo funziona correttamente. –

+2

perché non pubblicare l'algoritmo? psuedocodarlo? nulla? questa domanda è molto vaga e una risposta corretta dipende da molti fattori. –

risposta

3

È necessario formare una teoria per il motivo per cui si ritiene che l'algoritmo termini. Idealmente, dimostra la teoria come un teorema matematico.

È possibile cercare una funzione dello stato del problema che si riduce su ogni chiamata ricorsiva. Ad esempio, vedere la seguente discussione della funzione di Ackermann, da Wikipedia

Può non essere immediatamente evidente che la valutazione di A (m, n) termina sempre. Tuttavia, la ricorsione è limitata perché in ogni applicazione ricorsiva m diminuisce o m rimane uguale e n diminuisce. Ogni volta che n raggiunge lo zero, m diminuisce, quindi m raggiunge anche lo zero.(Espressa più tecnicamente, in ogni caso la coppia (m, n) diminuisce nell'ordine lessicografico su coppie, che è un buon ordinamento, proprio come l'ordinamento di singoli numeri interi non negativi, questo significa che non si può scendere nell'ordine infinite volte in successione). Tuttavia, quando m diminuisce, non vi è limite superiore su quanto può aumentare n e spesso aumenterà notevolmente.

Questo è il tipo di ragionamento che dovresti pensare di applicare al tuo algoritmo.

Se non riesci a trovare un modo per dimostrare che il tuo algoritmo termina, considera la possibilità di cercare una variante di cui puoi provare la risoluzione. Non è sempre possibile decidere se un programma arbitrario termina o meno. Il trucco è scrivere algoritmi che puoi provare a risolvere.

+0

+1, bella risposta. – dreamcrash

1

se si desidera verificare la presenza di un circuito senza fine,

scrivere la System.out.println("no its not endless"); alla prossima linea di chiamare la funzione ricorsiva.

se il ciclo sarebbe infinita, questa affermazione non otterrete di stampa, se altrimenti si vedrà l'uscita

+1

Non vero, il ciclo potrebbe essere osservato dopo aver attraversato molti percorsi. –

+0

@BorisStrandjev, non capisco davvero cosa intendi. se il programma è così 'callToRecursiveFunction()' allora se nella riga successiva scrivo 'System.out.println (" ");', non penso a meno che la funzione sopra riportata non restituisca un valore, cioè. uscire dalla ricorsione, l'SOP eseguirà –

+0

immaginando un'implementazione ricorsiva DFS. Può attraversare diversi percorsi semplici prima di incontrare il primo ciclo, che potrebbe essere l'unico fallimento. Se vuoi me posso fornirti il ​​codice. –

0

Un suggerimento è il seguente:

Se si dispone di loop infinito, allora nel caso del grafico si vuole ottenere un percorso con un numero di vertici maggiore del numero totale di vertici nel grafico. Supponendo che il numero di vertici nel grafico sia una variabile globale (che, penso, sia il caso più comune) è possibile eseguire un breakpoint condizionale all'inizio della ricorsione se la profondità è già superiore al numero totale di vertici.

Here is a link come si fanno i breakpoint condizionali per java in Eclipse.

+0

* alla fine * avresti attraversato un percorso con un numero di vertici maggiore del numero totale di vertici. forse l'input di OP è troppo grande perché ciò sia fattibile. se questo non fosse un algoritmo "complicato" super segreto, direi che è abbastanza facile rilevare se l'algoritmo è bloccato in un ciclo basato su dove ha attraversato in precedenza. ma chissà di cosa ha veramente bisogno l'op. forse all'OP è permesso di attraversare alcuni nodi più volte senza essere bloccato in un loop (che rompe la tua idea) –

+0

Nel mio caso non è così semplice. Innanzitutto il mio grafico non è costante. Algoritmo dovrebbe funzionare su grafici diversi. I grafici non hanno una struttura fissa. La connessione tra i nodi può dipendere da alcuni valori nei nodi. Inoltre i nodi possono essere visitati più volte. –

+0

@ ŁukaszRzeszotarski Naturalmente, la mia soluzione funziona con grafici generici, immessi dinamicamente dall'utente. È possibile rendere facilmente il punto di interruzione condizionale dipendente dalle variabili di classe, ad es. 'nodeNumber

1

È necessario conteggiare la profondità delle chiamate ricorsive ... e quindi generare un'eccezione se la profondità delle chiamate ricorsive raggiunge una determinata soglia.

Ad esempio:

void TheMethod(object[] otherParameters, int recursiveCallDepth) 
{ 
    if (recursiveCallDepth > 100) { 
     throw new Exception("...."); } 
    TheMethod(otherParameters, ++recursiveCallDepth); 
} 
+0

questo * potrebbe * funzionare in alcuni casi, ma non è una risposta concreta alla domanda delle operazioni. altamente dipendente dal contesto del problema. –

+0

@AlexLynch Ed è anche una variante di lancio del mio suggerimento per il punto di interruzione, che non so se sia meglio. –

3

migliore è dimostrando finitezza da condizioni, varianti e invarianti pre e post. Se è possibile specificare una formula (virtuale) il cui valore aumenta su ogni chiamata si ha una garanzia.

Questo equivale a provare i loop per essere finiti. Inoltre, potrebbe rendere più affrontabili algoritmi complessi.

Problemi correlati