Come primo esempio della tecnica divide et impera,
abbiamo considerato l'algoritmo per l'ordinamento
comunemente chiamato MergeSort.
Era questo un algoritmo ricorsivo
(trovi il codice tra le pagine web del corso)
che per ordinare elementi chiamava se stesso
su
degli elementi
da un lato, e sui restanti
dall'altro,
ed infine invocava una sottoprocedura, chiamata Merge,
il cui ruolo era quello di combinare in un'unica
lista ordinata gli elementi di due liste ordinate,
di
ed
elementi rispettivamente.
Il numero di confronti impiegato dalla sottoprocedura Merge era ,
nel caso peggiore.
Solo per richiamarvi il contesto di riferimento, potete provare a porvi la seguente domanda.
Inoltre, tra le pagine web del corso, trovate parziali risposte alla seguente domanda, che inquieta le notti della nostra procedura Merge.
Ma lo scopo di questa dispensa è l'affrontare assieme la seguente domanda.
Si indichi pertanto con il massimo numero di confronti che MergeSort sarà chiamato ad eseguire nell'ordinare una sequenza di numeri.
Ad onor del vero, avevamo già fornito alcune risposte parziali alla Domanda 3. Ad esempio, ragionando in termini di alberi dei confronti, avevamo visto che tali alberi binari dovevano avere altezza almeno , e ne avevamo concluso che un qualsiasi algoritmo di ordinamento basato sul confronto si ritrovava costretto a compiere almeno confronti nel caso peggiore. Ne consegue che , dacchè MergeSort non potrà costituire eccezzione.
Se siamo così fortunati, se la funzione ci appare regolare, allora forse abbiamo qualche speranza di trovare una semplice forma chiusa che esprima in modo esatto. Ma prima di procedere, e solo per rendersi conto della fortuna avuta, si completi e compendi l'esercizio sopra con il seguente.
Usare quindi GNUPLOT per tracciare il grafico di . Cosa vien fuori? Vien fuori una funzione continua e regolare? Se sì, allora vuol dire che questo è davvero un caso fortunato. Non ce lo saremmo davvero aspettato visti gli arrotondamenti presenti nella ricorrenza.
Ebbene, la ragione c'è ed è molto importante,
delicata, ed interessante.
Se non vi riesce ancora di coglierla (è anche sottile),
provate allora a scrivere sia un codice iterativo che uno ricorsivo
per la tabulazione della ricorrenza
Va bene, ci siamo accorti sperimentalmente che l'andamento di è regolare e questo ci fa ben sperare di riuscire ad ottenere un' espressione esplicita per in forma chiusa. A questo scopo consigliamo di differenziare la ricorrenza 1, ossia di ricavare da essa la ricorrenza che definisca la quantità . Otterremo così una ricorrenza più semplice, la soluzione della quale comporterà automaticamente la soluzione della ricorrenza originaria.
E tuttavia vogliamo ora proporre in questa occasione un ulteriore modo di andare a risolvere ricorrenze: quello di andare a capirle nella loro natura e riconoscerle.
Ora, se le ricorrenze per e fossero anche solo simili, ciò potrebbe portare alla soluzione della ricorrenza per qualora la soluzione per fosse già presente nel mio repertorio. Di fatto questo approccio alla soluzione delle ricorrenze prende il nome di metodo del repertorio. Potrà a prima vista sembrare un approccio poco soddisfacente, ma a ben vedere, come anche in altri contesti, non possiamo sminuire importanza e ruolo dell'arte di collegare un nuovo problema a problemi già incontrati e classificati vuoi nel bene (classificati come risolti) come nel male (rimasti irrisolti o dimostrati irrisolvibili, almeno in una qualche ben definita accezzione). Non vorremmo infatti nè continuare a reinventare ettolitri su ettolitri di acqua calda, nè perdere il nostro tempo su una ricorrenza sostanzialmente equivalente ad una famigerata ricorrenza su cui hanno misurato insuccessi, od hanno già determinato risposte negative, i grandi matematici che ci hanno preceduto. Nel caso delle ricorrenze poi, guardare ad una stessa ricorrenza da più punti di vista può condurci in semplicità alla soluzione. Anche gli alpinisti più audaci scelgono prima la parate da cui converrà tentare la scalata.
Nel seguente esercizio, ci permettiamo di indicare una via interessante.
Se ignoriamo gli zeri posti a sinistra, il numero di bits nella rappresentazione binaria di è per , ossia, prendendo il logaritmo, per . In definitiva, e quindi .
Avendo trovato una forma chiusa ed esatta per la quantità , dovremmo ora essere in grado di ricostruire la soluzione esatta per la .
Cosa vuol dire risolvere una ricorrenza per iterazione? Beh, proviamo ad applicare iterativamente la definizione della ricorrenza.
Non ci deve sorprendere la facilità con cui abbiamo saputo iterare in questo caso, in fondo la quantità appariva una sola volta sul lato destro della ricorsione, e quindi non avevo diramazioni da gestire.
La discussione di cui sopra conduce al seguente risultato.
Vorremmo però un' espressione, magari meno magica, ma più esplicita.
Ora, tutti gli interi positivi inferiori ad contribuiscono alla sommatoria con un bit di destra (bit meno significativo); in aggiunta, di essi contribuiscono alla sommatoria con un secondo bit (un bit in seconda posizione); in aggiunta, di essi contribuiscono alla sommatoria con un terzo bit (un bit in terza posizione); e così via ... . Pertanto
Ovviamente, è una funzione discontinua. Chi di voi aveva però tabulato la , aveva invece avuto modo di osservare un andamento continuo. Deve pertanto accadere che i contributi delle due funzioni della quantità discontinua nell'espressione della si elidano a vicenda. Essendo a conoscenza di questa cancellazione, ùn' operazione di routine mettere in evidenza questo fatto, e pervenire ad una forma analitica ancor più soddisfacente. A tale scopo, indicata con la parte frazionaria di , si sostituisca fuori la grandezza eliminandola dall'espressione di . Ciò dovrebbe condurre al seguente risultato.