Università degli studi di Messina – Facoltà di Ingegneria
Corso di Laurea in Ingegneria Informatica e delle Telecomunicazioni
Fondamenti di Informatica
II
Prof. D. Bruneo
Algoritmi di
Ordinamento e di
Ricerca
Introduzione
Ordinare una sequenza di informazioni significa effettuare una
permutazione in modo da rispettare una relazione d’ordine tra gli
elementi della sequenza (p.e. minore o uguale ovvero non
decrescente)
Input:
una sequenza di n numeri < a1 , a2 ,..., an >
Output:
una permutazione degli n elementi
< a1' , a2' ,..., an' >
tale che, data una funzione di ordinamento f:
f ( a1' ) ≤ f ( a2' ) ≤ ... ≤ f ( an' )
Fondamenti di Informatica II
Prof. D. Bruneo
2
Importanza dell’ordinamento
Uno dei maggiori problemi a cui fare fronte quando si manipolano
grosse quantità di informazioni è quello relativo all’ordinamento ed
al reperimento delle stesse
Un buon ordinamento garantisce una maggiore facilità di ricerca di
tali informazioni
Sia il sistema operativo che i software applicativi devono
continuamente effettuare ricerche su insiemi di informazioni e
quindi l’efficienza degli algoritmi di ordinamento usati è un fattore
critico per garantire le buone prestazioni del sistema
Fondamenti di Informatica II
Prof. D. Bruneo
3
Elemento di Informazione
In genere tutti gli elementi di informazione della sequenza hanno la
stessa struttura
Le struttura dell’elemento è in genere complessa e viene vista
come un insieme di campi di informazione
Per esempio la struttura di un elemento della sequenza di elementi di
una rubrica telefonica è:
Struttura: nome - cognome - numero
Fondamenti di Informatica II
Prof. D. Bruneo
4
Campi chiave
L’ordinamento di una sequenza viene fatto scegliendo almeno
un campo, definito chiave, che è quello utilizzato per la ricerca
nella sequenza.
In pratica ricerchiamo le informazioni di tutto l’elemento
utilizzando una parte nota di esso, la chiave
È molto comune la ricerca per più di un campo (chiavi multiple)
Le chiavi vanno scelte in modo da ridurre le possibili omonimie
Ad esempio nella rubrica cerchiamo principalmente per
cognome e poi per nome
L’ordinamento è quindi spesso effettuato su più di un campo:
chiave primaria, secondaria, ecc.
Fondamenti di Informatica II
Prof. D. Bruneo
5
Esempio
1. Rossi Paolo 090456789
2. Rossi Carlo 090435612
3. Bianchi Agata 090353678
Considerando lo scopo applicativo, la sequenza va ordinata per cognome
e nome, in ordine non decrescente.
Si ottiene così:
1. Bianchi Agata 090353678
2. Rossi Carlo 090435612
3. Rossi Paolo 090456789
Fondamenti di Informatica II
Prof. D. Bruneo
6
Operazioni Elementari
Si nota come siano necessarie operazioni di:
Confronto
Scambio
Risulta inoltre intuitivo come possa essere necessario scandire
più volte, magari su sottoinsiemi via via più piccoli la sequenza
informativa
Fondamenti di Informatica II
Prof. D. Bruneo
7
Valutazione degli algoritmi di ordinamento
I criteri generali per valutare un algoritmo di ordinamento sono:
Complessità computazionale
•Caso migliore
•Caso medio
•Caso peggiore
Esibizione di un comportamento naturale
Comportamento nel caso di elementi con chiave uguale (stabilità)
Fondamenti di Informatica II
Prof. D. Bruneo
8
Complessità computazionale
È importante avere un indicatore di confronto tra i vari algoritmi
possibili di ordinamento, indipendentemente dalla piattaforma
hw/sw e dalla struttura dell’elemento informativo
La complessità computazionale si basa sul numero di operazioni
elementari necessarie
Si misura come funzione del numero n di elementi della sequenza
Gli algoritmi di ordinamento interno si dividono in:
• Algoritmi semplici - complessità O(n2)
• Algoritmi evoluti - complessità O(n*log(n))
Fondamenti di Informatica II
Prof. D. Bruneo
9
Performance di esecuzione
È sempre indipendente dalla piattaforma hw/sw, ma
dipende dalla struttura dell’elemento informativo e dal
numero di chiavi usate:
➔
➔
Scambiare tra loro due integer a 32 bit è molto meno
oneroso che scambiare due struct complesse
Confrontare solo una chiave è meno oneroso che
confrontare due chiavi
Fondamenti di Informatica II
Prof. D. Bruneo
10
Indici delle sequenze
Per migliorare la performance di esecuzione è
utile costruire un vettore ausiliare (indice) che contiene i
puntatori agli elementi della sequenza.
I confronti verranno fatti sempre sugli elementi della sequenza ma lo scambio
viene fatto sulla sequenza dei puntatori
Fondamenti di Informatica II
Prof. D. Bruneo
11
Ordinamenti interni ed esterni
Vi sono due diverse categorie di algoritmi di ordinamento:
algoritmi che ordinano oggetti ad accesso casuale, come gli array,
e algoritmi che ordinano oggetti sequenziali, quali file su disco.
Si possono, quindi, distinguere:
Ordinamenti interni: sono fatti su sequenze in memoria centrale
Ordinamenti esterni: sono fatti su sequenze in memoria di massa
Fondamenti di Informatica II
Prof. D. Bruneo
12
Ipotesi semplificativa
Supporremo che la sequenza di informazioni sia
rappresentabile come vettore di n elementi,
ovvero ogni elemento sia individuabile tramite un
indice variabile da 0 a n-1.
Gli elementi del vettore potranno essere tipi scalari
(integrali o virgola mobile) o aggregati (struct)
Il vettore può essere allocato staticamente o
dinamicamente
Fondamenti di Informatica II
Prof. D. Bruneo
13
Classi di algoritmi di ordinamento
Vi sono tre metodi generali per ordinare i vettori:
scambio (bubble sort, quick sort)
selezione (selection sort)
inserimento (insertion sort, shell sort)
Fondamenti di Informatica II
Prof. D. Bruneo
14
Bubble Sort
Si tratta di un algoritmo semplice.
È un algoritmo di scambio.
Il nome deriva dalla analogia dei successivi spostamenti che
compiono gli elementi dalla posizione di partenza a
quella ordinata simile alla risalita delle bolle di aria in un
liquido.
Il bubbling si può realizzare in molte versioni basate sullo
stesso principio.
Fondamenti di Informatica II
Prof. D. Bruneo
15
Esempio
passo 1
passo 2
3
1
9
3
5
9
Ad ogni passo si confronta l’ultimo
REGOLA elemento con i precedenti scambiandolo
nel caso in cui risulti minore
7
5
2
7
1
Si confronta il numero 1 con i precedenti.
Essendo il più piccolo risalirà fino alla
prima posizione
2
Si confronta il numero 2 con i precedenti
(escluso il primo elemento) risalendo fino
alla seconda posizione
Si confronta il 7 con l’elemento
precedente (5): essendo il 7>5 non viene
effettuato lo scambio. Sarà invece il 5 a
risalire fino alla quarta posizione
passo 3
1
2
3
9
5
7
passo 4
1
2
3
5
9
7
passo 5
1
2
3
5
7
9
Fondamenti di Informatica II
Si confronta il 7 con il 9 scambiando gli
elementi
A questo punto il vettore risulta ordinato
Prof. D. Bruneo
16
Descrizione informale
Si consideri un vettore di n elementi.
Si vuole ordinare in ordine non decrescente
Facciamo “risalire le bolle dal fondo”
Sono necessarie diverse scansioni del vettore (iterazioni)
Inizializziamo a 0 il flag ordinato (ipotizziamo il vettore disordinato)
Scriviamo un ciclo for che controlla le n-1 iterazioni necessarie
ma che termina se il flag ordinato è 1, con ciò indicando che
la precedente iterazione intermedia ha già ordinato il vettore
Fondamenti di Informatica II
Prof. D. Bruneo
17
Descrizione informale (cont.)
La prima iterazione (i=0) si applica a tutto il vettore (n elementi) e posiziona
correttamente il primo elemento.
La seconda iterazione si applica a tutto il vettore escluso il primo elemento
(n-1 elementi).
L’i-esima iterazione si applica al sottovettore residuo, in quanto i primi i elementi
sono già stati ordinati.
L’ultima iterazione (i=n-2) si applica agli ultimi due elementi del vettore.
Se durante la generica iterazione c’è uno scambio, settiamo a 0
il flag ordinato, in modo che il for esterno che controlla le iterazioni sia informato
che il vettore non può ancora essere considerato ordinato.
Fondamenti di Informatica II
Prof. D. Bruneo
18
Descrizione informale (cont.)
In ogni scansione, iniziamo puntando l’indice all’ultimo elemento del vettore e
lo confrontiamo col precedente.
Se l’ultimo elemento è minore dobbiamo scambiarlo con il penultimo.
Se c’è lo scambio, poniamo a 0 il flag ordinato (indichiamo così che c’e’ stato
uno scambio ed il vettore non potrà essere considerato ordinato alla fine della
iterazione corrente).
Quindi il for interno di controllo verifica se deve fare un successivo confronto;
in tal caso l’indice risale di una posizione.
Per esempio nel secondo ciclo si confronta il penultimo con il terzultimo.
Fondamenti di Informatica II
Prof. D. Bruneo
19
Codice del Bubble Sort
#include <stdio.h>
#include <alloc.h>
void scambia(int ve[], int i, int j)
{
int tmp=ve[i];
ve[i]=ve[j];
ve[j]=tmp;
}
Fondamenti di Informatica II
void BubbleSort(int v[], int n)
{
int ordinato,i,j;
ordinato=0;
for (j=0;j<n-1 && !ordinato;j++)
{
ordinato=1;
for (i=n-1;i>j;i--)
{
if (v[i]<v[i-1])
{
scambia(v,i,i-1);
ordinato=0;
}
}
}
}
Prof. D. Bruneo
20
Codice del Bubble Sort (cont.)
void main()
{
//algoritmo bubble sort
//con allocazione dinamica di un vettore di
//interi
int n,i, *p;
//acquisizione da tastiera del numero degli
//elementi del vettore
do
{
printf("Quanti elementi deve avere il vettore?:");
scanf("%d",&n);
}
while (n<2 || n>50);
//allocazione degli n elementi del vettore
p=(int*)malloc(n*sizeof(int));
//acquisizione degli elementi del vettore
Fondamenti di Informatica II
for (i=0;i<n;i++)
{
printf("Immetti il valore dell'elemento
%d del vettore. V[%d]=",i,i);
scanf("%d",p+i);
}
BubbleSort (p,n);
//visualizza il vettore ordinato
for (i=0;i<n;i++)
printf("V[%d]=%d\n",i,*(p+i));
getchar();
}
Prof. D. Bruneo
21
Complessità del Bubble Sort
L’algoritmo BubbleSort esegue alla prima iterazione al più
n-1 confronti/scambi.
Alla seconda iterazione n-2 confronti/scambi
Le iterazioni sono in totale al più n-1
Il numero totale al più di confronti/scambi è:
(n-1)+(n-2)+…+1 ovvero:
n−1
n−1∗n
Kn=∑ i=
2
i=1
Fondamenti di Informatica II
e quindi la complessità risulta:
T n=O n2 
Prof. D. Bruneo
22
Selection Sort
Si tratta di un algoritmo semplice
È un algoritmo di selezione
Si seleziona l’elemento con il valore più basso e
lo si scambia con il primo elemento
Fra i rimanenti n-1 elementi si trova l’elemento con la chiave
più piccola e lo si scambia con il secondo
Si procede fino allo scambio degli ultimi due elementi
Fondamenti di Informatica II
Prof. D. Bruneo
23
Esempio
Ad ogni passo si seleziona l’elemento
REGOLA minore e lo si scambia con il primo
elemento non ordinato
passo 1
3
9
5
7
2
1
passo 2
1
9
5
7
2
3
passo 3
1
2
5
7
9
3
passo 4
1
2
3
7
9
5
Si seleziona l’elemento minore (il sesto
che ha valore 1) e lo si scambia con
l’elemento nella prima posizione
Si seleziona (tra tutti gli elementi escluso
il primo) l’elemento minore (il 2) e lo si
scambia con l’elemento in seconda
posizione
Si seleziona tra i 4 elementi rimasti il più
piccolo (il 3) e lo si scambia con
l’elemento in terza posizione
Si seleziona il 5 e lo si scambia con il 7
passo 5
1
2
3
5
9
7
Si scambiano gli ultimi due elementi
passo 6
1
2
Fondamenti di Informatica II
3
5
7
9
A questo punto il vettore risulta ordinato
Prof. D. Bruneo
24
Codice del Selection Sort
#include <stdio.h>
#include <alloc.h>
void main()
{
int n,i, *p;
//acquisizione da tastiera del numero degli
//elementi del vettore
do
{
printf("Quanti elementi deve avere il vettore?:");
scanf("%d",&n);
}
while (n<2 || n>50);
//allocazione degli n elementi del vettore dall'heap
p=(int*)malloc(n*sizeof(int));
//acquisizione degli elementi del vettore
void SelectionSort(int *v, int dim)
{
int i,j,k,elem;
int scambia;
for (i=0;i<dim-1;i++) {
scambia=0;
k=i;
elem=v[i];
for (j=i+1;j<dim;j++) {
if (v[j]<elem) {
k=j;
elem=v[j];
scambia=1;
}
}
if(scambia){
v[k]=v[i];
v[i]=elem;
}}}
Fondamenti di Informatica II
for (i=0;i<n;i++)
{
printf("Immetti il valore dell'elemento
%d del vettore. V[%d]=",i,i);
scanf("%d",p+i);
}
SelectionSort (p,n);
//visualizza il vettore ordinato
for (i=0;i<n;i++)
printf("V[%d]=%d\n",i,*(p+i));
getchar();
}
Prof. D. Bruneo
25
Complessità del Selection Sort
Il ciclo esterno verrà eseguito n-1 volte
Il ciclo interno viene eseguito una media di ½ n volte
Il risultato è che l’algoritmo di selezione richiede ½ (n2-n) selezioni/scambi
quindi:
T n=O n2 
Il tempo di esecuzione dipende solo in modo modesto dal grado di
ordinamento della struttura
Nonostante il numero di confronti sia uguale al numero di confronti effettuati
nel Bubble Sort, il numero di scambi dell’algoritmo Selection Sort risulta
essere molto inferiore; ciò lo rende preferibile nel caso di ordinamento di
strutture estremamente grandi con chiavi molto piccole.
Fondamenti di Informatica II
Prof. D. Bruneo
26
Insertion Sort
Si tratta di un algoritmo semplice
È un algoritmo di inserimento
L’algoritmo ordina innanzitutto i primi due elementi dell’array
Quindi si inserisce il terzo elemento nella posizione corretta
rispetto ai primi due elementi
Il processo continua fino all’inserimento (e quindi
all’ordinamento) di tutti gli elementi
Fondamenti di Informatica II
Prof. D. Bruneo
27
Esempio
Si ordinano i primi due elementi
REGOLA dopodiché si inseriscono ad uno ad uno
gli altri in maniera ordinata
passo 1
3
9
5
7
2
1
passo 2
3
9
5
7
2
1
passo 3
3
5
9
7
2
1
3
5
7
9
2
1
passo 4
Si ordinano i primi due elementi che in tal
caso risultano già ordinati
Si seleziona il terzo elemento (il 5) e lo si
inserisce in maniera ordinata nel vettore
composto dai primi due elementi
Si seleziona il quarto elemento (il 4) e lo
si inserisce in maniera ordinata nel
vettore composto dai primi tre elementi
Si inserisce il quinto elemento
passo 5
2
3
5
7
9
1
Si inserisce l’ultimo elemento
passo 6
1
2
Fondamenti di Informatica II
3
5
7
9
A questo punto il vettore risulta ordinato
Prof. D. Bruneo
28
Codice dell’Insertion Sort
void main()
{
int n,i, *p;
//acquisizione da tastiera del numero degli
//elementi del vettore
do
{
printf("Quanti elementi deve avere il vettore?:");
scanf("%d",&n);
}
while (n<2 || n>50);
//allocazione degli n elementi del vettore dall'heap
p=(int*)malloc(n*sizeof(int));
//acquisizione degli elementi del vettore
#include <stdio.h>
#include <alloc.h>
void InsertionSort(int *v, int dim)
{
int i,j,elem;
for (i=1;i<dim;i++) {
elem=v[i];
for (j=i-1;(j>=0) && (elem<v[j]);j--)
v[j+1]=v[j];
v[j+1]=elem;
}
}
Fondamenti di Informatica II
for (i=0;i<n;i++)
{
printf("Immetti il valore dell'elemento
%d del vettore. V[%d]=",i,i);
scanf("%d",p+i);
}
InsertionSort (p,n);
//visualizza il vettore ordinato
for (i=0;i<n;i++)
printf("V[%d]=%d\n",i,*(p+i));
getchar();
}
Prof. D. Bruneo
29
Complessità dell’Insertion Sort
A differenza del Bubble Sort e del Selection Sort, il numero di confronti che
avvengono con l’Insertion Sort dipende dal livello di ordinamento iniziale
del vettore.
Se il vettore è ordinato, il numero di confronti è pari a n-1, altrimenti i confronti sono
dell’ordine di n2
In generale, nei casi peggiori, l’Insertion Sort, non è più efficiente del Bubble Sort e
del Selection Sort, mentre nei casi medi è solo leggermente più veloce
Nonostante il numero di confronti (in alcuni casi) sia molto basso gli elementi del
vettore devono essere traslati ogniqualvolta che un elemento viene inserito nella
posizione corretta. Ciò rende il numero di spostamenti molto alto
quindi:
T n=O n2 
Fondamenti di Informatica II
I vantaggi dell’Insertion Sort sono dovuti al fatto che
esso si comporta in maniera naturale (manipola di
più i vettori disordinati e di meno quelli ordinati).
Esso va quindi usato nel caso di elenchi quasi
ordinati.
Prof. D. Bruneo
30
Shell Sort
Si tratta di un algoritmo evoluto
Deve il suo nome al suo ideatore D. L. Shell
È un algoritmo di inserimento
Il metodo di ordinamento si basa sulla riduzione degli incrementi
Si confrontano tutti gli elementi che si trovano ad una distanza d
e si continua riducendo il valore di d fino ad arrivare agli elementi
adiacenti (d=1)
Fondamenti di Informatica II
Prof. D. Bruneo
31
Esempio
REGOLA
confronti
passo 1
3
9
5
7
2
1
scambi
Si confrontano gli elementi distanti d,
scambiandoli nel caso non siano ordinati.
Quindi vengono ordinati gli elementi
diminuendo il valore di d fino ad arrivare ad 1.
In questo esempio si sono scelti valori di d pari a:
3,2,1
Si confrontano gli elementi distanti tre
posizioni scambiandoli nel caso il primo
sia maggiore del secondo
passo 2
3
2
1
7
9
5
Si confrontano gli elementi distanti 2
posizioni (3 - 1 - 9 e 2 - 7 - 5)
riordinandoli (1 - 3 - 9 e 2 - 5 - 7)
passo 3
1
2
3
5
9
7
Adesso si riduce la distanza ad uno e si
confrontano gli elementi adiacenti,
eventualmente scambiandoli
passo 4
1
2
3
5
7
9
A questo punto il vettore risulta ordinato
Fondamenti di Informatica II
Prof. D. Bruneo
32
Considerazioni
Sebbene lo Shell Sort sia facile da capire intuitivamente, una sua
analisi formale risulta difficile
In particolare, la valutazione dei valori ottimali della distanza d
(detta spaziatura) sfugge ai teorici
Si possono usare diverse spaziature per implementare lo Shell Sort. Di
solito si ordina l’array con una spaziatura grande, si riduce la spaziatura,
e si riordina l’array
L’unico vincolo da rispettare è che nell’ultimo passo la spaziatura valga
uno
Ad esempio, la sequenza 9,5,3,2,1 funziona molto bene
Sono da evitare le sequenze formate dalle potenze di 2 che, per complessi
motivi matematici, riducono l’efficienza dell’algoritmo (pur conservandone
l’efficacia)
Fondamenti di Informatica II
Prof. D. Bruneo
33
Codice dello Shell Sort
#include <stdio.h>
#include <alloc.h>
void ShellSort(int * vett, int dim)
{
int i,j,gap,k;
int x, a[5];
a[0]=9;a[1]=5;a[2]=3;a[3]=2;a[4]=1;
for (k=0;k<5;k++){
gap=a[k];
for(i=gap;i<dim;i++){
x=vett[i];
for(j=i-gap;(x<vett[j]) && (j>=0); j=j-gap)
vett[j+gap]=vett[j];
vett[j+gap]=x;
}
}
}
Fondamenti di Informatica II
void main()
{
int n,i, *p;
//acquisizione da tastiera del numero degli
//elementi del vettore
do
{
printf("Quanti elementi deve avere il vettore?:");
scanf("%d",&n);
}
while (n<2 || n>50);
//allocazione degli n elementi del vettore dall'heap
p=(int*)malloc(n*sizeof(int));
//acquisizione degli elementi del vettore
for (i=0;i<n;i++)
{
printf("Immetti il valore dell'elemento
%d del vettore. V[%d]=",i,i);
scanf("%d",p+i);
}
ShellSort (p,n);
//visualizza il vettore ordinato
for (i=0;i<n;i++)
printf("V[%d]=%d\n",i,*(p+i));
getchar();
}
Prof. D. Bruneo
34
Complessità dello Shell Sort
L’algoritmo Shell Sort risulta essere migliore, in termini di prestazioni,
degli algoritmi semplici (Bubble Sort, Selection Sort, Insertion Sort)
Intuitivamente, tale miglioramento deriva dal fatto che lo Shell Sort sposta
velocemente gli elementi nelle loro destinazioni
La complessità media è O(n1.25), mentre quella del caso peggiore diventa
O(n1.5)
quindi:
Fondamenti di Informatica II
T n=O n1,2 
mediamente
T n=O n1,5 
caso peggiore
Prof. D. Bruneo
35
Quick Sort
Si tratta di un algoritmo evoluto che ha complessità computazionale
O(n)=n*log(n)
È un algoritmo di scambio
È un algoritmo ricorsivo
Ricordiamo che la ricorsione consiste nell’esprimere F(n) in funzione di
F(n-1) ed inoltre nel conoscere il valore iniziale F(0)
Gli algoritmi ricorsivi sono più semplici ed eleganti, ma la loro
esecuzione comporta, a causa della annidarsi della funzione che si
richiama da se un uso a volte esagerato dello stack
È anche disponibile un’implementazione in ANSI-C di qsort, una
funzione C standard di libreria che viene tipicamente implementata con
il quicksort. Le chiamate ricorsive sono state sostituite da operazioni
dirette sullo stack
Fondamenti di Informatica II
Prof. D. Bruneo
36
Approccio informale
Si consideri un vettore di n elementi e lo si ordini con algoritmi semplici, con
un tempo di calcolo proporzionale a n2.
Si supponga, invece di dividere il vettore da ordinare in due sottovettori di n/2
elementi ciascuno e di ordinare le due metà separatamente.
Applicando sempre gli algoritmi non evoluti, si avrebbe un tempo di calcolo
pari a (n/2)2 + (n/2)2=n2/2.
Se riunendo i due sottovettori ordinati si potesse riottenere il vettore originario
tutto ordinato avremmo dimezzato il tempo di calcolo
Se questo ragionamento si potesse applicare anche immaginando una
decomposizione del vettore originario in quattro, si avrebbe un tempo di
calcolo totale pari a: (n/4)2+(n/4)2+(n/4)2+(n/4)2=n2/4
Se si potesse dividere in 8, si avrebbe un tempo ancora più basso, e
così via dicendo.
Fondamenti di Informatica II
Prof. D. Bruneo
37
Descrizione
L’algoritmo Quick Sort si basa sull’idea delle partizioni.
La procedura generale consiste nella selezione di un valore (detto
pivot) e nella suddivisione del vettore in due sezioni.
Tutti gli elementi maggiori o uguali al valore del pivot andranno da
una parte e tutti i valori minori dall’altra.
Questo processo viene ripetuto per ognuna delle sezioni rimanenti
fino all’ordinamento dell’intero vettore.
Fondamenti di Informatica II
Prof. D. Bruneo
38
Esempio
REGOLA
pivot
i
3
passo 1
7
pivot
i
passo 2
5
3
2
4
j
1
j
9
9
sezione 1
passo 3
1
2
j
7
5
sezione 2
3
4
5
7
Si sceglie il quarto elemento (valore 4
come elemento pivot
2
pivot
i
4
1
9
Si seleziona l’elemento pivot e si spostano gli
elementi più piccoli alla sua sinistra e i più grandi
alla sua destra. Si suddivide, quindi, il vettore in due
sezioni e si procede ricorsivamente
Si seleziona, partendo dall’estremità
sinistra, il primo elemento maggiore o
uguale del pivot e, partendo
dall’estremità destra, il primo elemento
minore o uguale del pivot. Dopodiché si
scambiano e si continua fino alla
scansione di tutti gli elementi (i<=J)
Si divide il vettore in due sezioni e si
procede ricorsivamente sulle due sezioni
scegliendo gli elementi pivot
Si scorrono gli elementi delle due sezioni
selezionando e scambiando gli elementi
che risultano maggiori (da sinistra) e
minori (da destra) dei rispettivi pivot
A questo punto il vettore risulta ordinato
Fondamenti di Informatica II
Prof. D. Bruneo
39
Considerazioni
L’esempio precedente si riferisce al caso migliore che avviene quando la scelta
dell’elemento pivot ricade sull’elemento mediano del vettore comportando una
suddivisione del vettore in sezioni di pari dimensioni
Il caso peggiore avviene quando il vettore viene decomposto in due sottovettori,
di cui il primo ha dimensione uguale alla dimensione originaria meno 1, e l’altro
ha una dimensione unitaria. Il pivot coincide con l’elemento massimo del vettore
La scelta dell’elemento pivot risulta, quindi, essere determinante
Se si fosse in grado di risalire all’elemento mediano la scelta ricadrebbe su di
esso. Normalmente tale operazione comporta una conoscenza a priori sul vettore
o un’analisi opportuna il cui tempo deve essere preso in considerazione
Il metodo più usato rimane quello della scelta casuale dell’elemento pivot,
selezionando, ad esempio, l’elemento che occupa la posizione centrale
Fondamenti di Informatica II
Prof. D. Bruneo
40
Esempio - caso peggiore
i
Se scegliamo come pivot l’elemento di posto
centrale (indice m=(inf+sup)/2),
ovvero il 34, questo, casualmente, coincide con
l’elemento maggiore del vettore.
pivot
13
20
1
15
34
28
21
14
29
3
pivot
13
20
1
15
3
28
i
21
14
29
34
j
L’indice i viene incrementato fino a quando non viene trovato un
elemento più grande o uguale al pivot. Nel nostro esempio
l’indice i si arresta in corrispondenza del pivot.
L’esempio mette in evidenza il motivo di incrementare l’indice i
fino a quando si trova un elemento più grande o uguale al pivot.
Se non ci fosse la condizione uguale, nel nostro esempio l’indice
i verrebbe continuamente incrementato oltre la dimensione del
vettore.
Per quanto riguarda l’indice j esso non viene spostato in quanto
l’elemento j-esimo è inferiore al pivot.
Gli elementi di indice i e j vengono scambiati, e l’indice i viene
incrementato, mentre j viene decrementato.
L’indice i viene quindi fatto incrementare fino a quando arriva
all’elemento 34, che è pari al pivot. L’indice j non viene fatto
decrementare perché si riferisce ad un elemento già inferiore al
pivot.
13
20
Siccome i > j, la prima passata è finita: otteniamo le seguenti sezioni
Fondamenti di Informatica II
1
15
3
28
sezione 1
21
14
29
34
sezione 2
Prof. D. Bruneo
41
Esempio - caso peggiore (cont.)
Come si vede l’esempio considerato rappresenta un caso
peggiore, perché il vettore originario è stato decomposto in due
vettori di cui il primo (quello compreso tra inf e j) ha dimensione
quasi uguale a quella originaria.
E’ chiaro che la complessità di riordino del primo sottovettore è
praticamente la stessa di quella relativa al riordino del vettore
originario.
Dunque non si è avuto alcun vantaggio nel suddividere il vettore.
Fondamenti di Informatica II
Prof. D. Bruneo
42
Codice del Quick Sort
int main(){
int partition(int v[], int l, int r){
int i=l-1,j=r;
int pivot=v[r]; //si piglia come elemento pivot
// l'ultimo elemento
for(;;){
while(v[++i]<pivot) ;
while(v[--j]>pivot)
if(j==l) break;
if(i>=j) break;
scambia(v,i,j);
}
scambia(v,i,r); //mette l'elemento pivot
// nella giusta posizione
return i;
}
int n,i, *p;
//acquisizione da tastiera del numero degli
//elementi del vettore
do{
printf("Quanti elementi deve avere il vettore?:");
scanf("%d",&n);
}
while (n<2 || n>50);
//allocazione degli n elementi del vettore dall'heap
p=(int*)malloc(n*sizeof(int));
//acquisizione degli elementi del vettore
for (i=0;i<n;i++){
printf("Immetti il valore dell'elemento %d
del vettore. V[%d]=",i,i);
scanf("%d",p+i);
}
quickSort (p,0,n-1);
void quickSort(int v[], int l, int r){
int i;
if(r<=l) return;
i=partition(v,l,r);
quickSort(v,l,i-1);
quickSort(v,i+1,r);
}
Fondamenti di Informatica II
//visualizza il vettore ordinato
for (i=0;i<n;i++)
printf("V[%d]=%d\n",i,*(p+i));
getchar();
}
Prof. D. Bruneo
43
Complessità del Quick Sort
Nel caso migliore, siccome l’array viene diviso in due ad ogni passo, e
l’algoritmo deve comunque esaminare tutti gli n elementi, il tempo di
esecuzione risulta O(n log(n)).
Nel caso peggiore ogni chiamata ricorsiva a quicksort ridurrebbe solo di
un’unità la dimensione dell’array da ordinare. Sarebbero quindi necessarie
n chiamate ricorsive per effettuare l’ordinamento, portando a un tempo di
esecuzione di O(n2).
Una soluzione a questo problema si può ottenere scegliendo a caso un
elemento come pivot. Questo renderebbe estremamente improbabile il
verificarsi del caso peggiore.
quindi:
T n=O nlog 2 n
T n=O n2 
Fondamenti di Informatica II
caso migliore e caso medio
caso peggiore (estremamente raro)
Prof. D. Bruneo
44
Quick Sort -analisi rigorosa
L’algoritmo è costituito da alcune assegnazioni, un ciclo for e due chiamate ricorsive.
Il ciclo for viene eseguito n +1 volte, quindi con un costo O(n).
Se n=1 la funzione costo è una costante.
Se n>1 bisogna considerare il costo delle chiamate ricorsive.
O (1)


T( n ) = 
O(n) + T(k) + T(n - k)

Fondamenti di Informatica II
n =1
n >1
Prof. D. Bruneo
45
Quick Sort -analisi rigorosa (cont.)
Si ha quando il pivot divide l’insieme degli elementi in due parti:
una composta da un solo elemento e l'altra dagli n-1 restanti.
Caso peggiore
T( n ) = O(n) + T (1) + T( n − 1) =
= O( n ) + O (1) + T (n-1) =
= O(n) + O(1) + O(n - 1) + O (1) + T (n- 2) =
= O ( n) + O(1) + O ( n − 1) + O(1) + O(n - 2) + O (1) + T( n-3)
generalizz ando :
k
T( n) = T(n - k) + ∑ O(n - i + 1)
i =1
La ricorsione si chiude quando k=n-1. In questo caso,
infatti, l'argomento di T() sarà pari ad uno e
arriveremo al caso banale T(1)=O(1), quindi:
n -1
T( n ) = T(1) + ∑ O(n - i + 1) =
i =1
 n

= O ∑ (n - i + 1)  =
 i =1

1

= O n (n + 1)  = O( n 2 )
2

Fondamenti di Informatica II
Prof. D. Bruneo
46
Quick Sort -analisi rigorosa (cont.)
Caso migliore
Si ha quando il pivot divide l’insieme degli elementi in
due parti uguali.
 n
 n
T( n ) = O(n) + T  + T  =
 2
 2
 n 
 n 
= O( n ) + 2O  + 2T  =
 4 
 2
 n 
 n
 n 
= O(n) + 2O  + 2 O   + 2T    =
 8 
 4
 2
n 
= O( n ) + O ( n ) + O ( n) + 8T 
8
generalizz ando :
k
 n 
T( n) = 2 T k  + ∑ O(n)
 2  i =1
La ricorsione si chiude quando n=2k.
In questo caso, infatti, l'argomento di
T() sarà pari ad uno e arriveremo al
caso banale T(1)=O(1), quindi:
k
T( n ) = nT(1) +
log2 n
∑ O(n) =
i =1
= O( n ) + O ( n log 2 n ) = O ( n log 2 n )
Fondamenti di Informatica II
Prof. D. Bruneo
47
Quick Sort -analisi rigorosa (cont.)
Tutti gli elementi possono essere presi come pivot con
probabilità 1/n. Anche la generica suddivisione i, n-i avviene
con probabilità 1/n.
Caso medio
1 n −1
1 n −1
T( n ) = O(n) + ∑ T(i ) + ∑ T( n − i )
n i =1
n i =1
1 n −1
= O( n ) + ∑ [ T(i ) + T (n − i) ] =
n i =1
sottraendo membro a membro:
nT(n) = (n + 1)T (n − 1) + 2O(n )
dividendo entrambi i membri per n(n+1):
2 n −1
= O( n ) + ∑ T(i )
n i =1
T(n) T(n - 1)
2
=
+
=
n +1
n
O(n + 1)
T(n - 2)
2
2
+
+
=
n -1
O( n) O( n + 1)
[...]
moltiplicando entrambi i membri per n si ottiene:
=
n −1
nT (n ) = nO(n) + 2∑ T (i )
i =1
n
T(2) n 2
1 n1
=
+∑
≅ 2∑ ≅ 2 ∫ dx = 2 ln( n)
3
i= 3 i + 1
i =1 i
1 x
che scritta per n-1 diventa:
n −2
(n - 1)T ( n - 1) = (n −1) O(n - 1) + 2∑ T (i )
quindi si ottiene:
i =1
Fondamenti di Informatica II
T (n ) = O(n ln(n ))
Prof. D. Bruneo
48
Merge Sort
Si tratta di un algoritmo evoluto che ha complessità computazionale
O(n)=n*log(n) anche nel caso peggiore
A differenza del Quick Sort è un algoritmo stabile
È un algoritmo ricorsivo
Si basa sul principio “divide et impera” sfruttando il concetto di fusione
(merging) di array ordinati
Fondamenti di Informatica II
Prof. D. Bruneo
49
Il merging a 2 vie - esempio
A(N)
3
B(M)
5
7
9
7
9
1
4
8
4
8
REGOLA
Ad ogni passo si seleziona l'elemento più piccolo tra
i due elementi di posto inferiore degli array e si
inserisce nell'array di uscita
5
7
9
4
8
1 3
5
7
1 3
4
9
Fondamenti di Informatica II
8
1 3
7
9
4
5
8
9
1 3
4
5
passo 7
1
passo 4
5
passo 5
3
passo 6
passo 3
passo 2
passo 1
C(N+M)
1 3
4
5
7 8 9
8
7
9
1 3
4
5
7 8
Prof. D. Bruneo
50
Il merging a 2 vie – codice
Tale implementazione necessita di un terzo array (di dimensione pari
alla somma delle dimensioni degli array di partenza) per contenere
l'output.
void mergeAB(int c[], int a[], int N, int b[], int M){
int i,j,k;
for(i=0,j=0,k=0;k<N+M;k++){
if(i==N){
c[k]=b[j++];
continue;
}
if(j==M){
c[k]=a[i++];
continue;
}
c[k] = (a[i]<b[j]) ? a[i++] : b[j++];
}
}
Fondamenti di Informatica II
Prof. D. Bruneo
51
Merging astratto sul posto
Tale implementazione utilizza ancora un array ausiliario di dimensione
proporzionale all'output, ma è più efficiente perchè evita di effettuare i
test sulla fine degli array.
Per fare ciò il secondo array viene trascritto in maniera inversa alla fine
del primo.
void merge(int a[], int l, int m, int r){
int i,j,k,*aux;
aux=(int*)malloc((r-l+1)*sizeof(int));
for(i=m+1;i>l;i--)
aux[i-1]=a[i-1];
for(j=m;j<r;j++)
aux[r+m-j]=a[j+1];
for(k=l;k<=r;k++)
if(aux[j]<aux[i])
a[k]=aux[j--];
else
a[k]=aux[i++];
}
Fondamenti di Informatica II
Prof. D. Bruneo
52
Merge Sort - descrizione
REGOLA
Per ordinare un dato array è sufficiente dividerlo in due, ordinare
(ricorsivamente) le due metà e fondere le sequenze ordinate
risultanti. La condizione di uscita della ricorsione si ha quando gli
array hanno una dimensione pari a uno.
3
9
3
9
3
3
9
5
5
7
7
2
3
9
5
1
8
4
9
3
5
1
5
5
7
3
7
7
7
9
4
2
2
2
1
1
5
1
1
1
2
8
4
8
4
8
2
4
8
8
4
4
divisione
Fondamenti di Informatica II
2
7
8
9
fusione
Prof. D. Bruneo
53
Codice del Merge Sort
int main(){
int n,i, *p;
//acquisizione da tastiera del numero degli
//elementi del vettore
do{
printf("Quanti elementi deve avere il vettore?:");
scanf("%d",&n);
}
while (n<2 || n>50);
//allocazione degli n elementi del vettore dall'heap
p=(int*)malloc(n*sizeof(int));
//acquisizione degli elementi del vettore
for (i=0;i<n;i++){
printf("Immetti il valore dell'elemento %d
del vettore. V[%d]=",i,i);
scanf("%d",p+i);
}
mergeSort (p,0,n-1);
void mergeSort(int a[], int l, int r){
if(r<=l)
return;
int m=(r+l)/2;
mergeSort(a,l,m);
mergeSort(a,m+1,r);
merge(a,l,m,r);
}
//visualizza il vettore ordinato
for (i=0;i<n;i++)
printf("V[%d]=%d\n",i,*(p+i));
getchar();
}
Fondamenti di Informatica II
Prof. D. Bruneo
54
Proprietà del Merge Sort
Il Merge Sort richiede all'incirca Nlog2N confronti per ordinare un
qualunque file di N elementi
Il Merge Sort utilizza uno spazio ausiliario proporzionale a N
Il Merge Sort è stabile, se il merging su cui si basa è stabile
Le risorse di tempo e spazio impiegate dal Merge Sort non dipendono
dall'ordinamento iniziale del file di input
Fondamenti di Informatica II
Prof. D. Bruneo
55
Ordinamento di strutture complesse
Finora si è parlato solo dell’ordinamento di array di interi. Ovviamente è possibile ordinare
array di un qualunque tipo di dati, semplicemente cambiando il tipo dei parametri e delle
variabili della funzione di ordinamento
I programmi applicativi che richiedono un ordinamento, in genere, organizzano gruppi di
dati più complessi
Ad esempio gli elenchi di indirizzi, gli archivi per inventari e le registrazioni contengono
raccolte di dati che, nei programmi C, vengono normalmente raccolte all’interno di
strutture
Anche se in genere una struttura contiene numerosi membri, deve essere ordinata sulla
base di un solo membro utilizzato come chiave dell’ordinamento
Ad eccezione della scelta della chiave, anche per l’ordinamento di strutture si impiegano
le tecniche già viste per gli altri tipi di dati
Fondamenti di Informatica II
Prof. D. Bruneo
56
Algoritmi di ordinamento esterno
L’algoritmo di ordinamento si
complica notevolmente quando
Memoria centrale
si trattano strutture dati
Alg.
ord.
complesse e articolate, quali file
o archivi.
Il problema è legato alla
File f
dimensione, in termini di
occupazione di memoria, della
struttura in questione: il metodo
f ordinato
f non ordinato
più semplice, efficace e veloce
per ordinare tale struttura è
trasferirla interamente in
File f
memoria e ivi ordinarla, ma
spesso le dimensioni non
consentono questo tipo di
Memoria di massa
operazione.
Fondamenti di Informatica II
Prof. D. Bruneo
57
KeySort
Una tecnica che consente, in alcuni casi, di superare il problema è quella del keysort.
Essa consiste nel creare una struttura in memoria, tipicamente un vettore, contenente il
campo chiave del record che costituisce l’unità di informazione. Inoltre bisogna
memorizzare la posizione iniziale del record all’interno del file.
L’ordinamento verrà fatto in memoria su tale struttura ed infine le modifiche verranno
riportate nel file.
Key
Pos
1
2
3
4
5
6
7
8
9
10
File f disordinato
Key
KeySort
Pos
3
7
5
8
1
9
2
4
6
10
File f ordinato
Memoria di massa
Fondamenti di Informatica II
Memoria centrale
Prof. D. Bruneo
58
KeySort: valutazioni
Non sempre questa tecnica risolve il problema:
➔
➔
➔
nei casi in cui il record è composto dalla sola chiave, non si trae alcun vantaggio
utilizzando il keysort, anzi, la struttura in memoria centrale è più pesante di quella in
memoria di massa, dovendo memorizzare l’informazione supplementare relativa alla
posizione del record nel file;
la tecnica si rivela insufficiente anche quando, pur trattandosi di record complessi e
strutturati, il vettore chiavi-indici assume una dimensione tale da non poter essere
contenuta in memoria;
altro problema è relativo alla scrittura del file ordinato: il metodo più semplice implica la
creazione di un nuovo file nel quale scrivere gli elementi secondo l’ordine specificato nel
vettore; ciò non sempre è possibile limitatamente alle capacità del dispositivo di
memorizzazione di massa. L’alternativa consiste nel leggere un dato file, ricercarlo nel
vettore in memoria centrale, risalire alla nuova posizione attraverso il campo pos, leggere
dal file l’elemento nella posizione in cui andrà scritto il primo dato (pos) e dunque
riscriverlo nella nuova posizione. Tutto ciò si traduce in un notevole dilatamento dei tempi
di esecuzione.
Fondamenti di Informatica II
Prof. D. Bruneo
59
Sort Merge
La soluzione ai problemi elencati, è, come anticipato, quella di scomporre il file in un
certo numero di parti, da ordinare in memoria centrale, e dunque fondere tali parti
ordinate in un unico file ordinato.
La tecnica utilizzata è nota in letteratura col nome Sort Merge, che, non a caso, richiama
alla memoria l’algoritmo di ordinamento Merge Sort, dal quale si ispira: la differenza è
che nel secondo caso si suddivide il vettore fino ad arrivare a vettori di un solo elemento
e solo allora comincerà l’operazione di fusione tra questi, mentre nell’algoritmo Sort
Merge la suddivisione del file produrrà un certo numero di piccoli sottoinsiemi di n
elementi detti run, che verranno ordinati in memoria centrale e dunque fusi.
file
run
Fondamenti di Informatica II
Prof. D. Bruneo
60
Sort Merge bilanciato a P vie
Si supponga di avere:
N record da ordinare su un dispositivo esterno
Spazio in memoria centrale per memorizzare M record
2P dispositivi esterni a disposizione durante l'ordinamento
Assegniamo l'etichetta 0 al dispositivo esterno contenente l'input
e le etichette 1, 2, ..., 2P-1agli altri dispositivi.
L'obiettivo dell'algoritmo è quello di riscrivere i record nel dispositivo 0,
in modo ordinato.
Fondamenti di Informatica II
Prof. D. Bruneo
61
L’algoritmo
1.
Il file iniziale viene suddiviso fra i dispositivi di input P, P+1, ..., 2P -1, in blocchi ordinati
di M record ciascuno (tranne eventualmente il blocco finale, che sarà più piccolo se N
non è multiplo di M).
2.
Dopo questa fase di distribuzione, il numero di blocchi ordinati su ciascun dispositivo è
pari a N/(MP) arrotondato all'intero precedente o successivo.
3.
Nel primo passaggio si considerano i dispositivi da P a 2P-1 come dispositivi di input e
quelli da 0 a P-1come dispositivi di output.
4.
Si esegue un merging a P vie per fondere i blocchi ordinati di dimensione M sui
dispositivi di input in blocchi ordinati di dimensione PM, e quindi si distribuiscono fra i
dispositivi di output.
5.
Dopo questa fase, il numero di blocchi ordinati su ciascun dispositivo sarà N/(P2 M)
6.
Si itera il processo eseguendo un secondo passaggio di merging considerando i
dispositivi da 0 a P-1 come dispositivi di input e quelli da P a 2P-1 come dispositivi di
output.
7.
Continuando in questo modo, andando avanti e indietro fra i dispositivi 0, ..., P-1 e i
dispositivi P, ..., 2P-1, si aumenta la dimensione dei blocchi di un fattore P fino a
ottenere, prima o poi, un solo blocco ordinato sul dispositivo 0 o sul dispositivo P.
Fondamenti di Informatica II
Prof. D. Bruneo
62
Esempio
0
3
4
5
0
1
2
P=3 M=3 N=45
asortingandmergingexamplewithfortyfiverecords
aos dmn aex fht erv
irt egr lmp ort ceo
3
aadeeegggiiilmmnnnoprrstwx
4
cdeeffhioorrrsttvy
agn gin eiw fiy drs
aaginorst ffhiortty
0
aacddeeeeeffggghiiiilmmnnnoooprrrrrsstttvwxy
deggimnnr cdeeorrsv
aeeilmpwx
Fondamenti di Informatica II
Prof. D. Bruneo
63
Caso ideale
Ciascun file (dispositivo esterno) contiene un run
È sufficiente solo una merge phase
Sfortunatamente è di difficile realizzazione
• Ci vorrebbero tanti file quanti sono i run, ma poiché il
numero di file gestibili da programma è limitato, la
condizione non sempre è realizzabile.
Fondamenti di Informatica II
Prof. D. Bruneo
64
Complessità
Al fine di calcolare la complessità degli algoritmi di ordinamento esterno si assume che il costo delle
operazioni di read e write sui dispositivi esterni sia molto maggiore rispetto alle operazioni primitive
eseguite in memoria centrale.
Quindi viene totalmente ignorato il costo di un ordinamento se è eseguito interamente nella memoria
centrale.
Avendo 2P dispositivi esterni e memoria centrale sufficiente a ospitare M record, un Sort Merge basato
su un merge bilanciato a P vie richiede all'incirca un numero di passaggi pari a:
1log p  N / M 
Un passaggio è richiesto per la distribuzione sui dispositivi.
Se N=MPK, i blocchi sono tutti di dimensione MP dopo la prima fusione , MP2 dopo la seconda, MP3
dopo la terza, e così via.
L'ordinamento si completa dopo k=logP(N/M) passaggi.
Altrimenti, se MPK-1<N<MPK , l'effetto di blocchi incompleti o vuoti rende i blocchi di dimensione molto
variabile verso la fine del processo.
Comunque, il processo termina sempre dopo k=logP(N/M) passaggi.
Fondamenti di Informatica II
Prof. D. Bruneo
65
Complessità (cont.)
Ad esempio, se vogliamo ordinare 1 miliardo di record usando 6 dispositivi
e memoria interna sufficiente a contenere 1 milione di record, possiamo
eseguire un Sort Merge a 3 vie per un totale di 8 passaggi sui dati
(1 per la distribuzione iniziale e log31000=7 per il merging).
Avremo sequenze ordinate di 1 milione di record dopo il passo di distribuzione
iniziale, di 3 milioni di record dopo la prima fusione, di 9 milioni di record dopo
la seconda fusione, di 27 milioni di record dopo la terza fusione, ecc.
In pratica la decisione più importante da prendere nel Sort Merge
riguarda la scelta del valore P, cioè il numero di vie del merging.
Accesso sequenziale
-> P deve essere pari alla metà dei dispositivi
Accesso non sequenziale -> è possibile aumentare P diminuendo il numero
di passi, ma ciò farà crescere il numero di accessi
Fondamenti di Informatica II
Prof. D. Bruneo
66
Sort Merge polifase
Svantaggio del merging bilanciato a P vie:
usa attivamente solo circa la metà dei dispositivi durante il merging
➔
L'idea di base del Sort Merg polifase è quella di distribuire i blocchi ordinati
prodotti dalla selezione con sostituzione in modo un pò disuguale fra i
dispositivi a disposizione (lasciandone uno vuoto), e quindi di applicare una
strategia del tipo “fondi finchè non è vuoto”
0
1
2
3
4*1
6*1
2*1
17*1
7*1
3*1
1*1
4*3
2*3
1*3
2*5
1*5
1*9
1*17
Fondamenti di Informatica II
Prof. D. Bruneo
67
Sort Merge polifase (cont.)
Si dimostra che l'efficienza dell'algoritmo è maggiore se la distribuzione dei
blocchi ordinati avviene secondo la distribuzione di Fibonacci:
1,1,2,3,5,8,13,21, ...
Tale metodo consente di eseguire lo stesso lavoro con circa la metà
dell'hardware. Se il numero di dispositivi esterni è fissato, il merging polifase
risulta sempre più efficiente del merging bilanciato.
➔
Fondamenti di Informatica II
Prof. D. Bruneo
68
Ricerca
I database consentono ad un utente di ricercare un record sulla
base di una chiave
Per ricercare le informazioni in una struttura dati (ad esempio un
array) esistono due metodi a seconda che la struttura dati sia
ordinata o no
Ricerca sequenziale: opera su strutture dati non ordinate
Ricerca binaria : opera su strutture dati ordinate
I compilatori C forniscono la funzione bsearch() nell’ambito delle
funzioni di libreria standard
Fondamenti di Informatica II
Prof. D. Bruneo
69
Ricerca sequenziale
Per trovare le informazioni in un array non ordinato è necessario eseguire
una ricerca sequenziale che parte dal primo elemento e termina nel momento
in cui viene trovata una corrispondenza o alla fine dell’array
Questo metodo deve essere necessariamente utilizzato su tutti i dati non
ordinati ma può essere impiegato anche quando i dati sono ordinati
int sequential_search (int * v, int dim, int key){
int i;
for(int i=0;i<dim;i++)
if (key==v[i])
return i;
return -1; /*elemento non trovato*/
}
Fondamenti di Informatica II
Prof. D. Bruneo
70
Tempo di Ricerca della Ricerca
Sequenziale
Nel caso migliore, la ricerca sequenziale, deve verificare un solo elemento e
nel caso peggiore deve controllare tutti gli n elementi
È facile comprendere che una ricerca sequenziale richiederà, in media, il
controllo di n/2 elementi.
quindi:
n
T n=O  
2
Fondamenti di Informatica II
mediamente
Prof. D. Bruneo
71
Ricerca Binaria
Se i dati sono ordinati la ricerca può essere eseguita impiegando un metodo migliore
Si controlla l’elemento centrale
Se è maggiore rispetto alla chiave si eseguirà la ricerca sulla prima metà del vettore se no
sulla seconda
Si deve ripetere questa procedura fino a trovare l’elemento o finché non vi
saranno più elementi da cercare
Esempio
Si vuole trovare il 4 nell’array seguente
1
2
3
4
1
2
3
4
4
Fondamenti di Informatica II
5
6
7
8
9
Si legge il valore centrale (5) e poiché risulta maggiore della
chiave (4) si continua la ricerca sulla prima metà
Ora l’elemento centrale è 3 che risulta minore della chiave e
quindi la prima metà viene scartata
La ricerca continua e viene trovato l’elemento cercato
Prof. D. Bruneo
72
Codifica della Ricerca Binaria
int binary_search (int * v, int dim, int key){
int low,high,mid;
low=0; high=dim-1;
while(low<=high){
mid=(low+high)/2;
if(key<v[mid])
high=mid-1;
else if (key>v[mid])
low=mid+1;
else
return mid; /*trovato*/
}
return -1; /*elemento non trovato*/
}
Per applicare questa funzione ad
altre strutture di dati basta
modificare la parte di confronto
della routine
Fondamenti di Informatica II
Prof. D. Bruneo
73
Tempo di Ricerca della Ricerca Binaria
Nella ricerca binaria il numero di confronti nel caso peggiore è pari a: log2n
In un caso medio il numero di confronti sarà minore
Nel caso migliore è richiesto un solo confronto
quindi:
T n=O log 2 n
Fondamenti di Informatica II
caso peggiore
Prof. D. Bruneo
74