doc

annuncio pubblicitario
Esame del corso di ALGORITMI E STRUTTURE DATI - Appello del 7/7/2004 – Compito B
Tempo a disposizione: 120 minuti
1. Il tipo astratto Matrice NxN a elementi interi prevede, tra le altre, le operazioni seguenti: i)
A.elemento(i, j): data la matrice A NxN e due indici i e j minori o uguali a N, restituisce il valore
dell'elemento di A in posizione (i, j); ii) A.somma(B): date due matrici NxN A e B, restituisce la
loro matrice somma. Implementare il tipo astratto Matrice NxN con le operazioni elemento e
somma (e solo quelle).
Sol.: una semplice implementazione e’ la seguente:
public class MatriceNN {
private static final int N = 100;
private int M[][];
/* Membri privati per incapsulamento e information hiding */
/* Altre variabili di classe */
/* Costruttore */
public MatriceNN() {
M = new int[N][N];
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
M[i][j] = 0; /* Possibile inizializzazione */
}
/* Metodi */
public elemento(int i, int j) {
return M[i][j];
}
public MatriceNN somma(MatriceNN B) {
MatriceNN C = new MatriceNN();
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
C.M[i][j] = M[i][j] + B.M[i][j];
return C;
}
}
2. i) Si dia un esempio di input di caso migliore per l'algoritmo QuickSort su un array di 8 interi. Si
assuma che il pivot sia sempre l'elemento centrale dell'array. ii) Si mostri l'evoluzione
dell'algoritmo sull'input considerato.
Sol.: il caso migliore per la scelta del pivot considerata si ha quando l’elemento centrale di ciascun
sottoarray e’ anche il mediano, ossia l’elemento di mezzo se si considera il sottoarray in ordine
crescente. Esempio:
{4, 3, 2, 7, 12, 10, 8, 9}
Se il pivot viene scelto in posizione n/2 in ciascun sottoarray di dimensione n, allora il primo
pivot sara’ l’elemento in posizione 4 (ossia 7). Tale elemento e’ anche il mediano e rispetto ad esso
l’array e’ gia’ ordinato. I due sottoarray che si ottengono al primo livello della ricorsione sono {4,
3, 2} e {12, 10, 8, 9}, aventi per pivot rispettivamente gli elementi in posizione 1 (3) e in posizione
2 (8). Si ottengono cosi’ 4 sottoarray gia’ ordinati: {2}, {4}, {9} e {10, 12}.
3. Dimostrare che l’altezza di un albero 3-ario completo e’ O(log3n), dove n e’ il numero dei nodi.
Sol.: si veda la domanda n. 9 del terzo gruppo di esercizi svolti presenti sul sito.
4. Si supponga di avere a disposizione la classe IntHeap, che implementa un heap minimale a chiavi
intere. La classe ha i consueti metodi void insert(int val), int deleteMin() e int getMin(), nonche' il
metodo int size(), che restituisce il numero di chiavi presenti nell’heap. Si supponga poi di avere a
disposizione una classe IntStack, che implementa uno stack di interi, con i metodi void push(int
val), int top() e int pop(). i) Scrivere un metodo int getKMin(int k) di IntHeap che, dato un intero k,
restituisce la k-esima chiave (in ordine crescente) presente nell’heap oppure size()+1 se k > size().
L'heap deve rimanere inalterato (alla fine dell'operazione). ii) Dare un limite superiore accurato alla
complessita' di getKMin nel caso peggiore per heap con n elementi. Motivare la risposta.
Sol.: il k-esimo elemento puo’ essere facilmente restituito eseguendo k-1 invocazioni del metodo
deleteMin() e restituendo poi getMin(). L’unica complicazione e’ data dalla necessita’ di non
modificare l’heap. A tale scopo si puo’ usare uno stack per ripristinare lo stato iniziale dell’heap.
Una possibile implementazione e’ allora la seguente:
public int getKMin(int k) {
IntStack myStack = new intStack();
int val = 0; /* Conterra’ il k-esimo elemento */
for (int i = 0; i < k-1; i++)
myStack.push(deleteMin());
val = getMin();
for (int i = 0; i < k-1; i++)
insert(myStack.pop());
return val;
}
Per quanto riguarda la complessita’ si osservi che un’invocazione di deleteMin() ha costo O(log n).
Infatti tale metodo restituisce la chiave minima e poi esegue l’operazione heapify per ripristinare
l’heap. Considerando l’implementazione standard di heap, restituire il minimo costa O(1), mentre
l’operazione di heapify ha costo O(log n) nel caso peggiore. Lo stesso si puo’ dire per ciascuna
invocazione del metodo insert(): l’elemento viene inserito nella prima posizione disponibile
nell’array che implementa l’heap (costo O(1)) e poi fatto risalire alla posizione giusta, operazione il
cui costo e’ ancora una volta O(log n) nel caso peggiore. Poiche’ ciascun ciclo for e’ eseguito k-1
volte, il costo complessivo di un’invocazione del metodo getKMin() e’ O(k log n) nel caso
peggiore.
5. Si supponga di avere le seguenti classi, che insieme implementano grafi non diretti rappresentati
mediante liste di adiacenza. La lista di adiacenza di ciascun vertice e' implementata con un oggetto
Vector, mentre il grafo stesso e' un array di dimensione N di oggetti di classe Vertice:
public class Vertice {
String etichetta; /* Es.: per assegnare identificatori agli archi */
Vector listaAdiacenza; /* Contiene etichette dei vertici adiacenti */
/* Costruttore*/
/* Metodi */
}
public class Grafo {
private static final int N = 100; /* No. Max. di vertici */
private Vertice[] mioGrafo;
public Grafo() {/* Costruttore */
mioGrafo = new Vertice[N];
/* Altre istruzioni del costruttore */
}
/* Metodi */
} /* Fine della classe Grafo */
Si scriva un metodo boolean ad(int i, int j) della classe Grafo che, dati due interi i e j, restituisca
true se i vertici i-esimo e j-esimo sono adiacenti, false in caso contrario. Si ricordi che size()
restituisce il No. di elementi presenti in un Vector e get(i) restituisce l'i-esimo elemento presente.
Sol.: ricordando la rappresentazione di grafi mediante liste di adiacenza, mioGrafo[i] contiene
l’oggetto corrispondente all’i-esimo vertice, mioGrafo[j] quello corrispondente al vertice j-esimo. I
due vertici sono adiacenti qualora l’etichetta di mioGrafo[i] compaia nella lista di adiacenza di
mioGrafo[j] (o viceversa, essendo il grafo non diretto). Dunque una possibile implementazione del
metodo e’ la seguente:
public boolean ad(int i, int j) {
String e; /* Etichetta del vertice i-esimo */
if ((i > N) || (j > N))
return false; /* Errore !! */
e = mioGrafo[i].etichetta;
for (int k = 0; k < mioGrafo[j].size(); k++)
if (e.equals(mioGrafo[j].listaAdiacenza.get(k)))
return true;
return false;
}
Scarica