Indice
Prefazione alla quarta edizione
CAPITOLO
IX
1
Fondamenti di programmazione in Java
1.1 Per iniziare: classi, tipi e oggetti 1
1.1.1 Tipi di base 4
1.1.2 Oggetti 5
1.1.3 Tipi enumerativi 11
1.2 Metodi 12
1.3 Espressioni 17
1.3.1 Letterali 17
1.3.2 Operatori 17
1.3.3 Casting e autoboxing/unboxing nelle espressioni 20
1.4 Flusso di controllo 23
1.4.1 Le istruzioni if e switch 23
1.4.2 Cicli 25
1.4.3 Istruzioni esplicite di flusso di controllo 27
1.5 Gli array 29
1.5.1 Dichiarazione di array 30
1.5.2 Gli array sono oggetti 31
1.6 Semplici esempi di input e output 32
1.7 Un programma esemplificativo 35
1.8 Classi annidate e pacchetti 37
1.9 Stesura di un programma Java 40
1.9.1 Progetto 40
1.9.2 Pseudocodifica 40
1.9.3 Codifica 41
1.9.4 Testing e debugging 45
1.10 Esercizi 47
CAPITOLO
2
2.2 Ereditarietà e polimorfismo 55
2.3
2.4
2.5
2.6
CAPITOLO
3
Array, linked list e ricorsione
3.1 Impiego degli array 85
3.2
3.3
Progettazione orientata a oggetti
2.1 Obiettivi, princìpi e modelli 51
2.1.1 Obiettivi della progettazione orientata a oggetti 51
2.1.2 Princìpi della progettazione orientata a oggetti 52
2.1.3 Schema di progetto 54
2.2.1 Ereditarietà 55
2.2.2 Polimorfismo 57
2.2.3 Impiego dell’ereditarietà in Java 58
Le eccezioni 66
2.3.1 Lancio delle eccezioni 66
2.3.2 Cattura delle eccezioni 68
Interfacce e classi astratte 70
2.4.1 Realizzazioni delle interfacce 70
2.4.2 L’ereditarietà multipla nelle interfacce 72
2.4.3 Classi astratte 73
Casting e tipi generici 74
2.5.1 Casting 74
2.5.2 Tipi generici 78
Esercizi 80
3.4
3.1.1 Memorizzazione in un array degli elementi
di un gioco 85
3.1.2 Ordinamento di un array 91
3.1.3 Metodi java.util per array e numeri casuali 93
3.1.4 Un semplice sistema crittografico mediante stringhe
e array di caratteri 95
3.1.5 Array bidimensionali e giochi posizionali 97
Linked list semplici 101
3.2.1 Inserimento in una linked list semplice 102
3.2.2 Rimozione di un elemento in una linked list
semplice 105
Linked list doppie 105
3.3.1 Inserimento intermedio in una linked list
doppia 107
3.3.2 Rimozione di elementi intermedi
di una linked list 109
3.3.3 Una implementazione della linked list
doppia 110
Linked list circolari e ordinamento su linked list 112
VI
INDICE
© 978-88-08-07037-1
3.5
3.6
3.4.1 Linked list circolari e il gioco
«papera, papera, oca» 112
3.4.2 Ordinamento di una linked list 116
Ricorsione 116
3.5.1 Ricorsione lineare 122
3.5.2 Ricorsione binaria 126
3.5.3 Ricorsione multipla 128
Esercizi 130
CAPITOLO
4
Strumenti per l’analisi
5.3
5.4
CAPITOLO
6.1 Array list 197
4.1.1
4.1.2
4.1.3
4.1.4
4.1.5
4.1.6
4.2
4.3
4.4
CAPITOLO
6.2
6.3
6.4
6.5
5
Stack e code
5.1 Gli stack 167
5.2
5.1.1 Il tipo di dato astratto stack 167
5.1.2 Una semplice implementazione di uno stack basata
su array 169
5.1.3 Implementazione di uno stack mediante
linked list 174
5.1.4 Inversione di un array mediante uno stack 175
5.1.5 Controllo delle parentesi e dei tag HTML 177
Le code 181
5.2.1 La coda come tipo di dato astratto 181
5.2.2 Una semplice implementazione basata su array 182
6
Le liste e gli iteratori
4.1 Le sette funzioni utilizzate in questo libro 135
La funzione costante 135
La funzione logaritmica 135
La funzione lineare 137
La funzione n log n 137
La funzione quadratica 137
La funzione cubica e altre funzioni
polinomiali 139
4.1.7 La funzione esponenziale 140
4.1.8 Confronto delle velocità di incremento 141
Analisi degli algoritmi 142
4.2.1 Studi sperimentali 143
4.2.2 Operazioni primitive 145
4.2.3 Notazione asintotica 146
4.2.4 Analisi asintotica 150
4.2.5 Impiego della notazione O-grande 152
4.2.6 Un algoritmo ricorsivo per il calcolo
delle potenze 155
Semplici tecniche di dimostrazione 156
4.3.1 Dimostrazione mediante esempi 156
4.3.2 Dimostrazione per contrapposizione
e per assurdo 157
4.3.3 Induzione e invarianza rispetto a un ciclo 158
Esercizi 160
5.2.3 Implementazione di una coda mediante
linked list 185
5.2.4 Lo scheduler round robin 186
Code doppie 187
5.3.1 La coda doppia come tipo di dato astratto 187
5.3.2 Implementazione di una coda doppia 189
Esercizi 192
6.6
6.1.1 L’array list come tipo di dato astratto 197
6.1.2 Il pattern adattatore 198
6.1.3 Una semplice implementazione basata
sugli array 199
6.1.4 Una semplice interfaccia e la classe
java.util.ArrayList 200
6.1.5 Implementazione di una array list mediante
array estensibili 201
Node list 204
6.2.1 Operazioni basate sui nodi 205
6.2.2 Posizioni 205
6.2.3 Il tipo di dato astratto lista 206
6.2.4 Implementazione mediante liste doppiamente
linkate 208
Iteratori 213
6.3.1 L’iteratore e i tipi di dati astratti iterabili 213
6.3.2 Il ciclo for-each di Java 216
6.3.3 Implementazione di iteratori 216
6.3.4 Liste e iteratori in Java 218
Le liste come TDA e la Collections Framework 220
6.4.1 La Collections Framework di Java 220
6.4.2 La classe java.util.LinkedList 221
6.4.3 Le sequenze 222
Caso di studio: l’euristica move-to-front 223
6.5.1 Utilizzo di una lista ordinata e di una classe
innestata 224
6.5.2 Utilizzo di una lista con l’euristica
move-to-front 224
6.5.3 Possibili utilizzi di una favorite list 230
Esercizi 230
CAPITOLO
7
Gli alberi
7.1 Alberi in generale 235
7.2
7.1.1 Terminologia e proprietà 235
7.1.2 L’albero come tipo di dato astratto (TDA) 238
7.1.3 Implementazione di un albero 239
Algoritmi fondamentali sugli alberi 241
VII
INDICE
© 978-88-08-07037-1
7.3
7.4
7.2.1 Profondità e altezza 241
7.2.2 Attraversamento preorder 244
7.2.3 Attraversamento postorder 246
Alberi binari 250
7.3.1 Il TDA albero binario 251
7.3.2 Interfaccia Java dell’albero binario 252
7.3.3 Proprietà degli alberi binari 253
7.3.4 Una struttura collegata per gli alberi binari 255
7.3.5 Rappresentazione di un albero binario mediante
liste di array 262
7.3.6 Attraversamento di un albero binario 264
7.3.7 Il modello del template method 270
Esercizi 275
CAPITOLO
8.1 La coda a priorità come tipo di dato astratto 285
8.3
8.4
8.5
8.1.1 Chiavi, priorità e relazioni d’ordine totale 285
8.1.2 Entry e comparatori 287
8.1.3 Il TDA coda a priorità 289
8.1.4 Ordinamento con una coda a priorità 291
Implementazione di una coda a priorità mediante
una lista 292
8.2.1 Implementazione con una lista non ordinata 292
8.2.2 Implementazione con una lista ordinata 293
8.2.3 Ordinamento per selezione e ordinamento
per inserimento 295
Heap 297
8.3.1 La struttura dati heap 298
8.3.2 Alberi binari completi e loro rappresentazione 300
8.3.3 Implementazione di una coda a priorità mediante
uno heap 305
8.3.4 Una implementazione Java dello heap 309
8.3.5 Ordinamento heap (heap-sort) 310
8.3.6 Costruzione dal basso verso l’alto (bottom-up)
di uno heap* 313
Code a priorità adattabili 317
8.4.1 Metodi del TDA coda a priorità adattabile 317
8.4.2 Elementi consapevoli della posizione 318
8.4.3 Implementazione di una coda a priorità
adattabile 319
Esercizi 319
CAPITOLO
9.2.1
9.2.2
9.2.3
9.2.4
9.2.5
9.2.6
9.3
8
Le code a priorità
8.2
9.2 Tabelle hash 333
9
Mappe e dizionari
9.1 La mappa come tipo di dato astratto 329
9.1.1 Una semplice implementazione di una mappa
basata su una lista 332
9.4
9.5
9.6
I bucket array 333
Funzioni hash 334
Codici hash 334
Funzioni di compressione 337
Schemi per la gestione delle collisioni 339
Una implementazione Java di una tabella
hash 343
9.2.7 Fattori di carico e ripetizione della funzione
hash 343
9.2.8 Applicazione: conteggio della frequenza
di parole 347
Il dizionario come tipo di dato astratto 348
9.3.1 Dizionari basati su liste e audit trail 350
9.3.2 Implementazione di un dizionario mediante
tabella hash 352
9.3.3 Tabelle di ricerca ordinata e ricerca
binaria 352
Skip list 356
9.4.1 Operazioni di ricerca e aggiornamento
in una skip list 358
9.4.2 Un’analisi probabilistica delle skip list* 362
Estensioni e applicazioni dei dizionari 364
9.5.1 Entry consapevoli della posizione
nei dizionari 364
9.5.2 Il TDA dizionario ordinato 365
9.5.3 Database dei voli e insiemi di massimi 366
Esercizi 369
CAPITOLO
10
Alberi binari di ricerca
10.1 Alberi binari di ricerca 375
10.1.1 Ricerca 376
10.1.2 Operazioni di aggiornamento 377
10.1.3 Implementazione in Java 381
10.2 Alberi AVL 385
10.2.1 Operazioni di aggiornamento 387
10.2.2 Implementazione in Java 391
10.3 Alberi estesi 395
10.3.1 Estensione 395
10.3.2 In quali circostanze occorre eseguire
un’estensione 396
10.3.3 Analisi ammortizzata dell’estensione* 399
10.4 Alberi (2,4) 405
10.4.1 Alberi di ricerca multi-way 405
10.4.2 Operazioni di aggiornamento per gli
alberi (2,4) 410
10.5 Alberi red-black 415
10.5.1 Operazioni di aggiornamento 417
10.5.2 Implementazione in Java 426
10.6 Esercizi 431
VIII
INDICE
© 978-88-08-07037-1
CAPITOLO
11
Ordinamento, insiemi e selezione
11.1 Merge-sort (ordinamento per fusione) 437
11.1.1 Dividi-e-conquista 437
11.1.2 Array e liste di fusione 441
11.1.3 Tempo di esecuzione del merge-sort 443
11.1.4 Implementazioni Java del merge-sort 445
11.1.5 Merge-sort ed equazioni ricorsive* 448
11.2 Quick-sort (ordinamento veloce) 449
11.2.1 Quick-sort probabilistico 455
11.2.2 Quick-sort in loco 456
11.3 Limite inferiore degli ordinamenti 459
11.4 Bucket-sort e radix-sort 461
11.4.1 Bucket-sort (ordinamento a secchi) 462
11.4.2 Radix-sort (ordinamento a radice) 463
11.5 Confronto tra algoritmi di ordinamento 464
11.6 Il TDA insieme e le strutture union/find 466
11.6.1 Semplice implementazione di un insieme 467
11.6.2 Partizioni con operazioni di union e find 469
11.6.3 Implementazione di una partizione basata
su albero* 471
11.7 Selezione 474
11.7.1 Riduzione-e-ricerca 475
11.7.2 Selezione veloce probabilistica 475
11.7.3 Analisi della selezione veloce probabilistica 475
11.8 Esercizi 477
CAPITOLO
12
Elaborazione di testi
12.1 Operazioni su stringhe 485
12.1.1 La classe Java String 486
12.1.2 La classe Java StringBuffer 487
12.2 Algoritmi di pattern matching 488
12.2.1 Forza bruta 488
12.2.2 L’algoritmo di Boyer-Moore 489
12.2.3 L’algoritmo di Knuth-Morris-Pratt 492
12.3 I trie 496
12.3.1 I trie standard 498
12.3.2 I trie compressi 501
12.3.3 Trie suffissi 502
12.3.4 Motori di ricerca 505
12.4 Compressione di testi 506
12.4.1 L’algoritmo di codifica di Huffman 508
12.4.2 Il metodo greedy 508
12.5 Test di somiglianza del testo 509
12.5.1 Il problema della più lunga sottosequenza
comune (LCS) 509
12.5.2 Programmazione dinamica 510
12.5.3 Applicazione della programmazione dinamica
al problema LCS 510
12.6 Esercizi 513
CAPITOLO
13
I grafi
13.1 Il grafo come tipo di dato astratto 519
13.1.1 Il TDA grafo 524
13.2 Strutture dati per i grafi 524
13.2.1 La lista di lati 525
13.2.2 La lista delle adiacenze 527
13.2.3 La matrice delle adiacenze 528
13.3 Attraversamento dei grafi 530
13.3.1 Visita in profondità 530
13.3.2 Implementazione della visita in profondità 534
13.3.3 Visita in ampiezza 541
13.4 Grafi orientati 544
13.4.1 Attraversamento di un grafo orientato 546
13.4.2 Chiusura transitiva 548
13.4.3 Grafi orientati aciclici 551
13.5 Grafi pesati 554
13.6 Percorsi minimi 555
13.6.1 Algoritmo di Dijkstra 556
13.7 I minimum spanning tree 562
13.7.1 Algoritmo di Kruskal 566
13.7.2 L’algoritmo di Prim-Jarník 569
13.8 Esercizi 571
CAPITOLO
14
La memoria
14.1 Gestione della memoria 583
14.1.1 Gli stack nella macchina virtuale Java 583
14.1.2 Allocazione dello spazio nello heap di memoria 586
14.1.3 Garbage collection 588
14.2 Memoria esterna e memoria cache 590
14.2.1 La gerarchia delle memorie 590
14.2.2 Strategie di gestione della memoria cache 591
14.3 Ricerca esterna e alberi B-tree 595
14.3.1 Alberi (a, b) 596
14.3.2 B-alberi 598
14.4 Ordinamento nella memoria esterna 599
14.4.1 Fusione multi-way 600
14.5 Esercizi 601
Appendice A • Proprietà matematiche utili
Bibliografia
613
Indice analitico
619
605