Esempi di sofisticati algoritmi ricorsivi


14

Stavo spiegando il famoso algoritmo di selezione del tempo lineare deterministico ( mediano delle mediane) ad un amico.

La ricorsione in questo algoritmo (pur essendo molto semplice) è piuttosto sofisticata. Esistono due chiamate ricorsive, ognuna con parametri diversi.

Stavo cercando di trovare altri esempi di algoritmi ricorsivi così interessanti, ma non riuscivo a trovarne nessuno. Tutti gli algoritmi ricorsivi che ho potuto escogitare sono semplici ricorsioni di coda o semplici divisioni e conquiste (dove le due chiamate sono "uguali").

Puoi fornire alcuni esempi di ricorsione sofisticata?


Attraversare un labirinto o più in generale un grafico con una prima ricerca è un semplice esempio di ricorsione interessante.

In definitiva, penso che BFS non sia idoneo per la mia domanda, poiché può essere facilmente e naturalmente implementato usando una coda e un ciclo while.
Elektronaj

Che dire del backtracking nella risoluzione di enigmi e analisi? E gli algoritmi di classificazione e non classificazione presentano anche ricorsioni non standard.
uli

Algoritmi di memorizzazione
Kaveh,

2
@vzn: una coda non può sostituire uno stack. BFS è un caso speciale.
Raffaello

Risposte:


15

La mia ricorrenza preferita si presenta in algoritmi sensibili all'output per il calcolo degli scafi convessi, prima da Kirkpatrick e Seidel , ma in seguito ripetuti da altri. Sia il tempo di calcolare lo scafo convesso di n punti nel piano, quando lo scafo convesso ha h vertici. (Il valore di h non è noto in anticipo, a parte il limite banale h n .) L'algoritmo di Kirkpatrick e Seidel produce la ricorrenza T ( n , h ) = 3  o  h 3T(n,h)nhhhn. doven1,n23n/4en1+n2=neh1+h2=h

T(n,h)={O(n)if n3 or h3T(n1,h1)+T(n2,h2)+O(n)otherwise
n1,n23n/4n1+n2=nh1+h2=h

La soluzione è . Questo è un po 'sorprendente, dal momento che h non è il parametro suddiviso uniformemente. Ma in realtà, il caso peggiore della ricorrenza si verifica quando h 1 e h 2 sono entrambi relativi a h / 2 ; se in qualche modo magicamente h 1 è sempre costante, la soluzione sarebbe T ( n , h ) = O ( n )T(n,h)=O(nlogh)hh1h2h/2h1T(n,h)=O(n) .

Ho usato una variante di questa ricorrenza in uno dei miei primi documenti di topologia computazionale : dove

T(n,g)={O(n)Se n3 o g=0T(n1,g1)+T(n2,g2)+O(min{n1,n2})altrimenti
e g 1 + g 2 = g . Ancora una volta, la soluzione è O ( n log g ) e ilcasopeggiore siverifica quando entrambi nn1+n2=ng1+g2=gO(nlogg)n che sono sempre divise in modo uniforme.g

Ho dei problemi con la condizione "if or h = O ( 1 ) "; cosa vuol dire O qui? Esistono delimitazione globalmente costanti che n e h devono sottosquadro a finire in caso uno (e gli autori non si preoccupano di dare loro). Perché se lo leggo letteralmente (cioè interpreto entrambi O ( 1 ) nello stesso modo di O ( n ) nella stessa riga) il caso due non accade mai o sempre (non ne sono nemmeno sicuro). Abuso di notazione portato troppo lontano, imho. n=O(1)h=O(1)OnhO(1)O(n)
Raffaello

1
Mi dispiace, ho modificato la mia risposta per chiarire. significa "la tua costante preferita". Ho usato 3 nella mia revisione, ma 10 10 100 ! avrebbe funzionato altrettanto bene. O(1)31010100!
JeffE,

Come hai disegnato quei diagrammi nei documenti di topologia computazionale?
user119264,

12

Anche la ricorsione che ho usato nel mio articolo "Un algoritmo a tempo lineare per calcolare il diagramma di Voronoi di un poligono convesso" di Aggarwal et al è anche abbastanza complicata.

Ecco una descrizione dell'algoritmo dal nostro documento. Nel caso in cui non sia chiaro dalla descrizione, al punto 3 i punti rossi sono suddivisi in punti cremisi e granato. I passaggi 1, 3 e 6 sono tutti tempi lineari. Sappiamo anche che se è il numero totale di punti, | B | α n , | R | β n e | C | γ n per alcuni α , β , γ >n|B|αn|R|βn|C|γn .α,β,γ>0

Ti farò capire perché l'intero algoritmo richiede tempo lineare.

  1. Suddividere i punti originali nei set blu e rosso B e R.
  2. Calcola ricorsivamente lo scafo convesso dei punti blu.
  3. Usando la struttura dello scafo blu, selezionare i punti cremisi C.
  4. Aggiungi i punti cremisi allo scafo blu uno alla volta.
  5. Calcola ricorsivamente lo scafo convesso dei punti granato G.
  6. Unisci questo scafo granato con lo scafo blu espanso del passaggio 4.

Ciò che rende lineare l'algoritmo è la possibilità di aggiungere una frazione fissa dei punti rossi allo scafo blu a un costo costante per punto. I punti aggiunti sono i punti cremisi.

T(n)=T(|B|)+T(|sol|)+O(n)
|B||sol||B|+|sol|(1-γ)n

7

Esiste una variazione sulla ricorrenza della ricerca mediana che proviene dalla ricerca della distanza con mezzi aerei. La ricorrenza stessa è della forma

T(n)=T(n/2)+T(n/4)+cn
che è simile alla ricorrenza del ritrovamento mediano. Per ulteriori informazioni, guarda gli appunti di Jeff Erickson e in particolare la Sezione 4.

1
La mia risposta qui ( cs.stackexchange.com/questions/332/… ) sembra avere esattamente la stessa ripetizione per il suo tempo di esecuzione :)
Alex ten Brink

6

Ci sono un sacco di fantastici algoritmi ricorsivi [1], [2] usati nella previsione della struttura secondaria dell'RNA. Lasciato a se stesso, un filamento di RNA formerà coppie di basi con se stesso; un esempio relativamente semplice di [3] calcola il numero massimo di basi annidate e accoppiate che una stringa RNA formerà con se stessa:

M(io,j)=mun'XioK<j-Lmion{M(io,K-1)+M(K+1,j-1)+1M(io,j-1)


  1. Piegatura ottimale del computer di grandi sequenze di RNA utilizzando la termodinamica e le informazioni ausiliarie di M. Zuker, P. Stiegler (1981)

  2. Un algoritmo di programmazione dinamica per la previsione della struttura dell'RNA, inclusi gli pseudoknots di E. Rivas, SR Eddy (1999)

  3. Algoritmo rapido per la previsione della struttura secondaria dell'RNA a singolo filamento di R. Nussinov, AB Jacobson (1980)


Una correlata qui proposta è piuttosto complessa poiché sfoggia tre ricorsioni reciprocamente dipendenti (programmazione dinamica).
Raffaello

4

Non capisco ancora cosa intendi per "ricorsione sofisticata". Ad esempio, la fase di ricorsione nell'algoritmo FFT è sofisticata!

Ma se vuoi cercare una ricorsione più complicata , la ricorsione reciproca potrebbe essere una possibile risposta. La ricorsione reciproca è utile quando si lavora con linguaggi di programmazione funzionali . La ricorsione reciproca è la caratteristica chiave dei parser di discesa ricorsiva .


Bene, la ricorsione in FFT (la forma più semplice di Cooley-Tukey) è la divisione e la conquista "standard". Ciò è evidente dalla sua complessità O (nlogn). Le 2 chiamate ricorsive (1 per il pari, 1 per le probabilità) sono in qualche modo "uguali".
elektronaj,

3

Dalla parte superiore della mia testa, la funzione McCarthy 91

F(N) = 
    n - 100    if n > 100
    F(F(n+11)) if n <= 100

e la funzione Ackermann

A(m, n) = 
    n + 1             if m = 0
    A(m-1, 1)         if m > 0 and n = 0
    A(m-1, A(m, n-1)) if m > 0 and n > 0

potrebbe essere considerato come insolito, anche se giocattolo, funzioni ricorsive.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.