• Non ci sono risultati.

Algoritmi e Strutture Dati Laurea in Informatica

N/A
N/A
Protected

Academic year: 2021

Condividi "Algoritmi e Strutture Dati Laurea in Informatica"

Copied!
130
0
0

Testo completo

(1)

Algoritmi e Strutture Dati Laurea in Informatica

Calendario: 27 Febbraio – 13 Giugno Aula: LuM250

Orario: Mer 12.30-14.15

Gio, Ven 14.30-16.15 Numero crediti = 9 (~ 72 ore)

~ 52 ore di teoria, ~20 ore di esercizi Docenti: Paolo Baldan (5crediti)

Michele Scquizzato (4 crediti)

(2)

a. Prova intermedia

per l’assegnazione di un bonus fino a 3 punti (che si somma al voto dell’esame finale)

b. Prova scritta

(5 appelli - indispensabile iscriversi nella lista di esame che verrà attivata su UNIWEB)

c. Registrazione, con possibile orale (su base volontaria). Indispensabile per conseguire la lode.

Modalità d’Esame

(3)

Testo: Introduzione agli Algoritmi e Strutture Dati (3°

ed). T.H.Cormen, C.E.Leiserson, R.L.Rivest, C.Stein.

McGraw-Hill.

Pagina del corso:

www.math.unipd.it/~baldan/Algoritmi + Moodle con altro materiale

Trad. di: Introduction to Algorithms and Data Structures (3° ed). T.H.Cormen, C.E.Leiserson, R.L.Rivest,

C.Stein. MIT Press.

Materiale didattico

(4)

Programma

Le prime 5 parti del testo (con qualche omissione):

I. Fondamenti: notazione per gli algoritmi e primi esempi di algoritmi e di analisi degli algoritmi II. Ordinamento e statistiche d’ordine

III. Strutture dati fondamentali

IV. Tecniche avanzate di progettazione ed analisi degli algoritmi

V. Strutture dati avanzate

(5)

I problemi computazionali, gli algoritmi che li risolvono e le tecniche per sviluppare tali

algoritmi

INTRODUZIONE

Esempio1: problema dell’ordinamento

Input: a1,a2,...,an

Output: a'1,a'2,...,a'n permutazione (riarrangiamento) di a1,a2,...,an tale che a'1 £ a'2 £ ... £ a'n

(6)

TECNICA

INCREMENTALE

(7)

Soluzione1: Algoritmo Insertion-Sort.

InsertionSort

1 n

A

1 n

A

1 j n

A key

1 j n

A i

1 j n

A

j

1 n

A j

1 j n

A i

key

1 j n

Ai key

(8)

Insertion-Sort(A) n = A.length for j = 2 to n

key = A[j]

// inseriamo A[j] nella sequenza // ordinata A[1..j-1]

i = j - 1

while i > 0 and A[i] > key A[i+1] = A[i]

i = i – 1 A[i+1] = key

(9)

Insertion-Sort(A) n = A.length for j = 2 to n

key = A[j]

// inseriamo A[j] nella // sequenza ordinata // A[1..j-1]

i = j – 1

while i > 0 and A[i] > key A[i+1] = A[i]

i = i – 1 A[i+1] = key

void Insertion-Sort(vector<T> A) {

int i, j, n = A.size(); T key;

for (j = 1; j < n; j++) {

key = A[j];

// inseriamo A[j] nella // sequenza ordinata // A[0..j-1]

i = j – 1;

while (i >= 0 && A[i] > key) {

A[i+1] = A[i];

i--;

}

A[i+1] = key;

} }

(10)

Insertion-Sort(A) n = A.length

for j = 2 to n

// inserisce A[j] nella // sequenza ordinata // A[1..j-1]

key = A[j]

i = j – 1

while i > 0 and A[i] > key A[i+1] = A[i]

i = i – 1 A[i+1] = key A

5 2 8 4 7 1 3 6

key

5 # 8 4 7 1 3 6 2

# 5 8 4 7 1 3 6 2 5 8 4 7 1 3 6

2 5 # 4 7 1 3 6 8 2 5 # 4 7 1 3 6

2 5 8 4 7 1 3 6

2 5 8 # 7 1 3 6 4 2 # 5 8 7 1 3 6

2 4 5 8 7 1 3 6

2 4 5 8 # 1 3 6 7 2 4 5 # 8 1 3 6

2 4 5 7 8 1 3 6

(11)

Insertion-Sort(A) n = A.lenght

for j = 2 to n

// inserisce A[j] nella // sequenza ordinata // A[1..j-1]

key = A[j]

i = j – 1

while i > 0 and A[i] > key A[i+1] = A[i]

i = i – 1 A[i+1] = key A

2 4 5 7 8 1 3 6

key

2 4 5 7 8 # 3 6 1

# 2 4 5 7 8 3 6 1 2 4 5 7 8 3 6

1 2 4 5 7 8 # 6 3 1 2 # 4 5 7 8 6

1 2 3 4 5 7 8 6

1 2 3 4 5 7 8 # 6 1 2 3 4 5 # 7 8

1 2 3 4 5 6 7 8

(12)

Insertion-Sort(A) n = A.length

for j = 2 to n key = A[j]

i = j - 1

while i > 0 and A[i] > key

A[i+1] = A[i]

i = i – 1

A[i+1] = key

Analisi di Insertion-Sort: correttezza

Correttezza InsertionSort

1 j n

A

i

1 j n

A

1 j n

A

i

1 j n

A i

1 j n

A

(13)

Analisi di Insertion-Sort: complessità

Insertion-Sort(A) //

n = A.length //

for j = 2 to n //

key = A[j] //

i = j -1 //

while i > 0 and A[i] > key //

A[i+1] = A[i] //

i = i – 1 //

A[i+1] = key //

) 1

2(

5

å

= +

n

j tj

c c0

n c2

) 1

3(n - c

) 1

4(n - c

å

= n

j t j

c6 2

å

= n

j t j

c7 2

) 1

8(n - c

j t

j

<

£ 0

c1

å å

= + + + =

+

- +

+ +

+ +

=

n

j j

n

j j

IS

t c

c t

c

n c

c c

n c c

c n

T

7 2 2 6

5

8 4

3 2

1 0

) (

) 1 (

) 1 )(

( )

(

(14)

caso migliore:

å å

=

+ +

=

+

- +

+ +

+ +

=

n j n

j IS

c c

c

n c

c c

n c c

c n

T

7 2 2 6

5

8 4

3 2

1 0

min

0 )

( 1

) 1 )(

( )

(

= 0

t j 0 £ tj < j

a bn

c c

c c

c c

n c

c c

c c

n T IS

+

=

- -

- -

+ +

+ +

+ +

= ( ) ( )

)

( 2 3 4 5 8 0 1 3 4 5 8

min

(15)

caso peggiore: t

j

= j - 1

' '

'

) (

2 ) 1 2

1 2

( 1

) 2 (

) 1 (

2

8 4

3 1

0

8 7

6 5

4 3

2

2 7

6 5

max

a n

b n

c

c c

c c

c

n c

c c

c c

c c

n c

c c

n T IS

+ +

=

- -

- +

+

+ -

- +

+ +

+

+ +

=

j t

j

<

£ 0

å

å

= + + = - +

- +

+ +

+ +

=

n j n

j IS

j c

c j

c

n c

c c

n c c

c n

T

7 2 2 6

5

8 4

3 2

1 0

max

) 1 (

) (

) 1 )(

( )

(

(16)

caso medio:

å

å

=

-

=

+

+ +

+

- +

+ +

+ +

=

n j n j

j

j IS

c c

c

n c

c c

n c c

c n

T

2 2 7 1

2 2 6 5 1

8 4

3 2

1 0

med

) (

) 1 )(

( )

(

2 -1

=

j

t

j

"

"

"

) (

4 ) 1 4

1 4

( 3

) 4 (

) 1 (

2

8 5

4 3

1

8 7

6 5

4 3

2

2 7

6 5

med

a n

b n

c

c c

c c

c

n c

c c

c c

c c

n c

c c

n T

IS

+ +

=

- -

- -

+

+ -

- +

+ +

+

+ +

=

j t

j

<

£

0

(17)

TECNICA

DIVIDE ET IMPERA

(18)

5 2 8 0 4 7 1 9 3 2 6

0 4 7 2

5

5 2 8

5 2 8 0 4 7

5 2 8 0 4 7 1 9 3 2 6

2 6 1 9 3

1 9 3 2 6

9 1

4 0

5 2 8 0 4 7 1 9 3 2 6

5 2 8 0 4 7 1 9 3 2 6

5 2 8 0 4 7 1 9 3 2 6

5 2 8 2

5

0 4 7 1 9 3

4

0 1 9

6 2

0 1 2 2 3 4 5 6 7 8 9 0 2 4 5 7 8

2 5 8 2 5

5 2

8

1 2 3 6 9

0 4 7 1 3 9 2 6

0 4 7 1 9 3

4

0 1 9

6 2

Soluzione2: Algoritmo Merge-Sort

(19)

Merge-Sort(A,p,r) if p < r

q = ë(p+r)/2û

Merge-Sort(A,p,q) Merge-Sort(A,q+1,r) Merge(A,p,q,r)

(20)

L

0 2 4 5 7 8 1 2 3 6 9

0 2 4 5 7 8 ¥ R 1 2 3 6 9 ¥ A[p..q] A[q+1..r]

0

2 4 5 7 8 ¥ 1 2 3 6 9 ¥ 0 1

2 4 5 7 8 ¥ 2 3 6 9 ¥

0 1 2

4 5 7 8 ¥ 2 3 6 9 ¥

0 1 2 2

4 5 7 8 ¥ 3 6 9 ¥

0 1 2 2 3

4 5 7 8 ¥ 6 9 ¥

0 1 2 2 3 4

5 7 8 ¥ 6 9 ¥

0 1 2 2 3 4 5

7 8 ¥ 6 9 ¥

0 1 2 2 3 4 5 6

7 8 ¥ 9 ¥

0 1 2 2 3 4 5 6 7

8 ¥ 9 ¥

0 1 2 2 3 4 5 6 7 8

¥ 9 ¥

0 1 2 2 3 4 5 6 7 8 9

¥ ¥

A[p..r]

(21)

Merge(A,p,q,r) n1 = q – p + 1 n2 = r – q

for i = 1 to n1

L[i] = A[p + i – 1]

for j = 1 to n2

R[j] = A[q + j]

L[n1 + 1] = R[n2 + 1] = ¥ i = j = 1

for k = p to r

if L[i] £ R[j]

A[k] = L[i]

i = i + 1 else

A[k] = R[j]

j = j + 1

(22)

Merge-Sort(A,p,r)

if p < r // altrimenti A[p..r] è ordinato q = ë(p+r)/2û

Merge-Sort(A,p,q) Merge-Sort(A,q+1,r)

Merge(A,p,q,r)

Analisi di Merge-Sort: correttezza

non ordinati

1 p r n

A

ordinati

1 p r n

A

ordinati

1 p ordinati r n

A q

(23)

Merge(A,p,q,r) n1 = q – p + 1 n2 = r – q

for i = 1 to n1

L[i] = A[p + i – 1]

for j = 1 to n2 R[j] = A[q + j]

L[n1 + 1] = R[n2 + 1] = ¥ i = j = 1

for k = p to r if L[i] £ R[j]

A[k] = L[i]

i = i + 1 else

A[k] = R[j]

j = j + 1

1 p q r n

A

1 p r n

A

L R

1 n1 1 n2

1 p r n

A

L R

1 n1 1 n2

k

i j

1 p r n

A

L R

1 n1 1 n2

k

i j

(24)

Merge(A,p,q,r) // complessità //

n1 = q – p + 1 //

n2 = r – q //

for i = 1 to n1 //

L[i] = A[p + i – 1] //

for j = 1 to n2 //

R[j] = A[q + j] //

L[n1 + 1] = R[n2 + 1] = ¥ //

i = j = 1 //

for k = p to r //

if L[i] £ R[j] //

A[k] = L[i] //

i = i + 1 //

else

A[k] = R[j] //

j = j + 1 //

c1

c2

c3

( 1 1)

4 n + c

1 5n c4(n2 +1)

c

2 5n c

c6

ë(p r)/2û

q = +

2 11n c

c7

( 1)

8 n+ c

1 11n c

n c9

1 10n c

2 10n c

+1 -

= r p n

é /2ù

1 n

n =

ë /2û

2 n

n =

2

1 n

n n = +

' '

2

) (

) (

8 7

6 4

3 2

1

11 10

9 8

5 4

b n a

c c

c c

c c

c

n c

c c

c c

c n

T M

+

=

+ +

+ +

+ +

+

+ +

+ +

+

=

(25)

Merge-Sort(A,p,r) //complessità //

if p < r //

q = ë(p+r)/2û //

Merge-Sort(A,p,q) //

Merge-Sort(A,q+1,r) //

Merge(A,p,q,r) //

c1

c2

c3

( )n1

T MS

( )n2 T MS

( )n a'n b' TM = +

+1 -

= r p n

îí ì

>

+ +

+ +

+

£

= +

1 se

) ( )

( )

(

1 ) se

(

2 1

3 2

1

2 1

n n

T n

T n

T c

c c

n c

n c

T MS MS MS M

1 = q - p +1 n

q r n2 = -

2

1 n

n n = +

îí ì

>

+ +

+

= £

1 se

) (

) (

1 ) se

(

2

1 T n n

n T

b an

n n c

T MS MS MS

(26)

( )

n an

é

n

ù

b n cn

T MS @ log2 + ( -1) +

b

an1,1 + an1,2 + b an2,1 + b an2,2 + b

élog2 nù

c c c c c c c c c c c c

b an +

b an 2+

b an 4+

cn

( ) îíì + + ( )+ ( ) >

= £

1 se

1 se

2

1 T n n

n T

b an

n n c

TMS MS MS

b an +

( )n1

T MS TMS( )n2

b an1 +

( )

n1,1

T MS T MS( )n1,2

b an2 +

( )n2,1

T MS TMS( )n2,2

( )

n a'nlog2 n b'n c'

T MS @ + +

(27)

( ) ( )

lim ' "log " ' " ' 0

lim 2 2 =

+ +

+

= ®¥ +

¥

® a n b n c

c n

b n

n a n

T

n T

IS n med

MS n

Dunque esiste N tale che per ogni n > N.

Qualunque siano i valori delle costanti a', b', c', a", b" e c" l’algoritmo Merge-Sort è superiore a Insertion-Sort

per array di dimensione sufficientemente grande.

( )

n T

( )

n

T MS < medIS

( )

n a'nlog2 n b'n c'

T MS @ + +

"

"

"

)

(n a n2 b n c TmedIS = + +

(28)

Possiamo dire che “cresce come” n2 mentre “cresce come” n log2 n.

( )

n

TmedIS

( )

n

T MS

n n2 n log2 n

IS n2 ns

MS

n log2 n ns

10 100 33 0.1µs 0.033µs

100 10000 664 10µs 0.664µs

1000 106 9965 1ms 10µs

10000 108 132877 0.1s 133µs 106 1012 2·107 17m 20ms

109 1018 3·1010 30s

109 1018 3·1010 70anni 30s

(29)

( ) ( )

= ®¥ ++ + = ¥

¥

® " "

' '

log lim '

lim 2

b n

a

c n

b n

n a n

T

n T

IS n min

MS n

dunque esiste N tale che per ogni n > N.

Qualunque siano i valori delle costanti a', b', c', a", b" l’algoritmo Insertion-Sort è superiore a Merge-Sort per array (quasi) ordinati e

sufficientemente grandi.

( )

n T

( )

n

T MS > minIS

(30)

Insertion-Sort è anche superiore a Merge-Sort per array piccoli in quanto le costanti a', b', c' in sono generalmente molto maggiori delle costanti a", b" e c" in .

( )

n

T MS

( )

n

TmaxIS

Questo suggerisce una modifica di Merge-Sort in cui le porzioni di array di dimensione minore di una certa costante k si ordinano con Insertion-Sort invece di usare ricorsivamente Merge-Sort.

(31)

Soluzione3: Algoritmo Merge-Ins-Sort

Merge-Ins-Sort(A,p,r) if p < r

if r-p+1 < 32

InsertSort(A,p,r) else

q = ë(p+r)/2û

Merge-Ins-Sort(A,p,q) Merge-Ins-Sort(A,q+1,r) Merge(A,p,q,r)

(32)

Complessità e Notazione Asintotica

Quando si confrontano algoritmi, determinare il tempo di esecuzione

-È complicato

-Contiene dettagli inutili che vorremmo ignorare

-Dipende da costanti non note

vogliamo darne una visione più astratta (tasso di crescita)

(33)

Paragonare tra loro algoritmi

Abbiamo una scala di complessità:

vogliamo inserire ogni algoritmo in questa scala

1 log

log ...

2 ...

2 3

n n n n

n n

n

(34)

Un algoritmo può richiedere tempi diversi per input della stessa taglia. Ad esempio il tempo per ordinare n oggetti può dipendere dal loro ordine iniziale.

complessità massima

complessità minima complessità media

1 log

log ...

2 ...

2 3

n n n n

n n

n

(35)

Nell’analizzare la complessità tempo di un algoritmo siamo interessati a come aumenta il tempo al crescere della taglia n dell’input.

Siccome per valori “piccoli” di n il tempo richiesto è comunque poco, ci interessa

soprattutto il comportamento per valori

“grandi” di n (il comportamento asintotico)

(36)

Inoltre, siccome la velocità del processore influisce sul tempo calcolo per una costante moltiplicativa noi valuteremo la complessità a meno di una tale costante.

Questo giustifica le seguenti definizioni:

(37)

Notazione asintotica O

(limite superiore asintotico)

} ogni

per )

( )

( 0

che tali

ed 0

esistono :

) ( { ))

( (

0 0

n n

n cg n

f

n c

n f

n g

³

£

£

>

= O

) (n f

) (n cg

n0

O(g(n))

(38)

Scriveremo f(n) = O(g(n)) per dire che f(n) è una delle funzioni dell’insieme O(g(n))

f(n) = O(g(n)) si legge:

f(n) è “o grande” di g(n)

Se f(n) = O(g(n)) rappresenta il tempo calcolo richiesto da un algoritmo diciamo che

O(g(n)) è un limite superiore asintotico per la

complessità tempo di tale algoritmo.

(39)

esempi

) (

5 5

2 )

(n n2 n O n2

f = + + =

infatti 0 £ 2 n

2

+ 5 n + 5 £ cn

2

per c = 4 ed n

0

= 5

) 1 ( sin

2 )

( n n O

f = + =

infatti

0 £ 2 + sin n £ c ×1

per c = 3 ed n

0

= 1

) (

)

( n a

2

n

2

a

1

n a

0

O n

2

f = + + =

Vedremo che in generale per a

2

> 0

(40)

Notazione asintotica W . (limite inferiore asintotico)

} ogni

per 0

) ( )

(

che tali

ed 0

esistono :

) ( { ))

( (

0 0

n n

n cg n

f

n c

n f n

g

³

³

³

>

= W

) (n f

) (n cg

n0

(41)

Se f(n) = W(g(n)) rappresenta il tempo

calcolo richiesto da un algoritmo diciamo che W(g(n)) è un limite inferiore asintotico per la complessità tempo di tale algoritmo.

Scriveremo f(n) = W(g(n)) per dire che f(n) è una delle funzioni dell’insieme W(g(n)).

f(n) = W(g(n)) si legge:

f(n) è “omega” di g(n)

(42)

esempi

) (

5 5

2 )

(n n2 n n2

f = - - = W

infatti

0 £ cn2 £ 2n2 - 5n - 5

per c = 1 ed n

0

= 10

) 1 ( sin

2 )

(n = + n = W f

infatti

0 £ c ×1 £ 2 + sin n

per c = 1 ed n

0

= 1

) (

)

(n a2n2 a1n a0 n2

f = + + = W

Vedremo che in generale se a

2

> 0

(43)

Notazione asintotica Q . (limite asintotico stretto)

)}

( )

( )

( 0

ogni per

che tali

ed 0 ,

esistono :

) ( { ))

( ( ))

( ( ))

( (

2 1

0 0

2 1

n g c n

f n

g c

n n

n c

c

n f n

g n

g O n

g

£

£

£

³

>

= W

Ç

= Q

) (n f

)

1g(n c

n0

)

2g(n c

(44)

Se f(n) = Q(g(n)) rappresenta il tempo calcolo richiesto da un algoritmo diciamo che Q(g(n)) è un limite asintotico stretto per la

complessità tempo di tale algoritmo.

Scriveremo f(n) = Q(g(n)) per dire che f(n) è una delle funzioni dell’insieme Q(g(n)).

f(n) = Q(g(n)) si legge:

f(n) è “theta” di g(n)

(45)

esempi

) (

5 5

2n2 - n + = O n2 2n2 - 5n + 5 = W(n2)

2 2 2

2

1 2 5 5

0 £ c n £ n - n + £ c n per c1 = 1, c2 = 4 ed n0 = 10

) (

5 5

2n2 - n + = Q n2 Dunque

) 1 ( sin

2 + n = O

2 + sin n = W ( 1 )

) 1 ( sin

2 + n = Q

Dunque

(46)

) (

5 5

2 )

(n n2 n n3

f = + + ¹ Q

per ogni n ³ n0 allora

5 5

2

0 £ c1n3 £ n2 + n +

altrimenti

3 1 2

5 5

2

n n

c £ n + + per ogni n ³ n0. Assurdo!

) ( 5

5 2

)

(n n2 n n

f = + + ¹ Q

per ogni n ³ n0 allora n

c n

n2 5 5 2 2

0 £ + + £

altrimenti

n c n

n

2 2

5

2 + 5 + £ per ogni n ³ n0. Assurdo!

(47)

Metodo del limite

Spesso è possibile determinare dei limiti

asintotici calcolando il limite di un rapporto.

Ad esempio se

lim

n®¥

f ( n ) / g ( n ) = k > 0

allora per ogni e > 0 esiste n0 tale che per n ≥ n0

e

e £ £ +

- f n g n k

k ( ) / ( )

Preso 0 < e < k e posto c1 = k - e e c2 = k +e

) ( )

( )

(

2

1

g n f n c g n

c £ £

)) (

( )

( n g n f = Q

e quindi

(48)

Se diciamo che

Attenzione: quando il limite del rapporto non esiste questo metodo non si può usare.

¥

¥ =

® ( )

) lim (

n g

n f

n f (n) =

w

(g(n))

)) (

( )

(

ma

)) (

( )

( n g n f n g n

f = W ¹ Q

ed in questo caso

Se diciamo che0 )

( ) lim ®¥ ( =

n g

n f

n

f ( n ) = o ( g ( n ))

)) (

( )

(

ma

)) (

( )

(n O g n f n g n

f = ¹ Q

ed in questo caso

(49)

In generale f (n) = aknk +...+ a1n + a0 = Q(nk ) per ogni funzione polinomiale di grado k con coefficiente ak > 0.

Inoltre

b a

b

a

n

¹ Q

n

¹ Q ( ) ( ) per

b a

n

n b

a ) (log ) per ogni e

(log = Q Q

) (

) log

( n

k

n ¹ Q n

k

Q

h k

n

n

k

¹ Q

h

¹ Q ( ) ( ) per

n b

n a b

a log log

log

perché =

(50)

) (

) (

) log

(

) (

) (

) (log

n n

k

k h

b O

a O

n n

O

n O

n O

n O

Í Í

Í

Í Í

Í

) (

) (

) log

(

) (

) (

) (log

n n

k

k h

b a

n n

n n

n

Q

¹ Q

¹ Q

¹

¹ Q

¹ Q

¹ Q

Per 0 < h < k e 1 < a < b :

(51)

Useremo le notazioni asintotiche anche all’interno delle formule.

In questo caso le notazioni O(f(n)), Ω(f(n)) e

ϴ(f(n)) stanno ad indicare una qualche funzione appartenente a tali insiemi e di cui non ci

interessa conoscere la forma esatta ma solo il comportamento asintotico.

Ad esempio T(n)=n2+O(n) significa che T(n) è la somma di n2 e di una funzione che cresce al più linearmente.

(52)

esiste un algoritmo che risolve il problema con questa complessità

limite superiore: O(n2)

1 log

log ...

2 ...

2 3

n n n n

n n

n

Valutare la difficoltà dei problemi

(53)

Valutare la difficoltà dei problemi

ogni algoritmo che risolve il problema ha complessità

maggiore o uguale di questa limite inferiore: W(n)

1 log

log ...

2 ...

2 3

n n n n

n n

n

(54)

Un limite superiore per il problema dell’ordinamento

Abbiamo visto che Insert-Sort per ordinare n oggetti richiede O(n

2

) operazioni

Quindi O(n

2

) è un limite superiore

(55)

Vedremo in seguito che Q(n log n) è un limite stretto per il problema dell’ordinamento.

Per ora ci limitiamo a dimostrare che:

La complessità nel caso pessimo di ogni

algoritmo di ordinamento sul posto che confronta e scambia tra loro soltanto elementi consecutivi dell’array è W(n2).

Quindi il problema di ordinare sul posto un array scambiando tra loro soltanto elementi consecutivi ha complessità Q(n2).

(56)

Se l’array è ordinato non ci sono inversioni.

Se l’array è ordinato in senso opposto e gli

elementi sono tutti distinti allora ogni coppia (i, j) di indici con i < j è una inversione e quindi ci

sono esattamente n(n-1)/2 inversioni.

Sia A[1..n] un array

Se i < j e A[i] > A[j] diciamo che la coppia di indici (i, j) è una inversione

8 3

i j

3

k

(57)

Come cambia il numero di inversioni quando facciamo uno scambio tra due elementi

consecutivi A[i] ed A[i+1] dell’array?

Consideriamo tutte le coppie di indici ( j, k) con j < k e vediamo quante e quali di esse

possono cambiare di stato da inversioni a non inversioni o viceversa quando scambiamo

A[i] con A[i+1].

x

i i+1

y

(58)

Se j e k sono entrambi diversi da i e i+1 la coppia ( j, k) non cambia di stato e quindi il numero di inversioni di questo tipo non cambia.

y x

i i+1

u v

k j

(59)

(i, k) è inversione dopo lo scambio se e solo se (i+1, k) lo era prima e (i+1, k) è inversione se e solo se (i, k) lo era prima.

y x

i i+1

v

k

x y

i i+1

v

k

Quindi le due coppie si scambiano gli stati ma il numero totale di inversioni non cambia.

Consideriamo le due coppie (i, k) e (i+1, k) con k > i+1 ossia

(60)

y x

i i+1

u

j

x y

i i+1

u

j

La situazione è simmetrica di quella precedente e quindi anche in questo caso il numero totale di

inversioni non cambia.

Consideriamo le coppie (j, i) e (j,i+1) con j < i ossia

(61)

In conclusione con lo scambio di due elementi consecutivi dell’array il numero totale di

inversioni aumenta o diminuisce di 1 (o rimane invariato se i due elementi scambiati erano

uguali).

Rimane soltanto da considerare la coppia (i, i+1) che con lo scambio cambia di stato se i due

elementi sono diversi.

(62)

Nel caso pessimo in cui l’array è ordinato in senso inverso e gli elementi sono tutti distinti le

inversioni iniziali sono n(n-1)/2.

Siccome n(n-1)/2 = W(n2) rimane dimostrato il limite inferiore.

Occorrono quindi almeno n(n-1)/2 scambi tra elementi consecutivi per ridurre tale numero a 0.

(63)

Esercizio: Abbiamo dimostrato che scambiando due elementi diversi consecutivi il numero totale di inversioni aumenta o diminuisce di 1.

Quindi se prima dello scambio il numero di

inversioni totale era pari, dopo lo scambio esso risulta dispari e viceversa.

Mostrare che questo cambiamento della parità del numero totale di inversioni avviene anche se si

scambiano due elementi diversi non consecutivi.

(64)

Soluzione delle ricorrenze

Metodo di sostituzione:

Si assume che la soluzione sia di un certo tipo, ad esempio

3 2

2

1

log

)

( n k n n k n k

T = + +

dove k1, k2 e k3 sono delle costanti

Si sostituisce la soluzione nella ricorrenza e si cercano dei valori delle costanti per i quali la ricorrenza è soddisfatta.

Se le cose non funzionano si riprova con un altro tipo di soluzione.

Riferimenti

Documenti correlati

In pratica, modellando la cartina dell’Italia come un grafo orientato pesato G=(V, E), dove ciascun vertice rappresenta una città, ogni arco (u,v) rappresenta una strada diretta da

Infine, se la lista è doppiamente puntata, il puntatore prev della testa della lista punta all’elemento in coda

lista.h deve includere la definizione della struttura dati a puntatori (lista semplice non circolare) e i soli prototipi delle funzioni implementate in lista.c. Dunque, per

Un albero binario è una tipo astratto di dato che o è vuoto (cioè ha un insieme vuoto di nodi) o è formato da un nodo A (detto la radice) e da due sottoalberi, che sono a loro

Riversamento dei dati contenuti nell’heap nell’albero binario di ricerca utilizzando una visita lineare dell’array. Stampare i dati contenuti nell’albero binario di

La classe di memoria automatica è relativa a quegli oggetti locali ad un blocco (funzione o programma) che viene liberata non appena si raggiunge la fine di quel blocco. La classe

• Problemi polinomiali non deterministici = problemi risolvibili in tempo polinomiale da un algoritmo non deterministico, ma per i quali non è ancora stata trovata una.

Il limite inferiore Ω(n log n) vale per tutti gli algoritmi di ordinamento generali, ossia per algoritmi che non fanno alcuna ipotesi sul tipo degli elementi della sequenza