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.