Tempo: 120 minuti 1. Modificare l’algoritmo Selection Sort in modo che, dati un array di interi A e un intero k < A.length, l’algoritmo modificato restituisca il valore del k-esimo elemento (in ordine crescente) presente in A. Esempio: se A = {23, 3, 11, 4, 15, 5} e k = 2 il valore da restituire e’ 4. Stimare la complessita’ dell’algoritmo nel caso peggiore. Sol. un algoritmo che realizza l’operazione richiesta e’ il seguente: int kselection(int A[], int k) { int minIndex = 0; /* memorizza indice del minimo corrente */ int temp = 0; for (int i=0; i<k; i++) { minIndex = i; for (int j=i+1; j<n; j++) /* Cerca (i+1)-esimo elemento */ if (A[minIndex]>A[j]) minIndex = j; /* Elemento in pos. minIndex e’ (i+1)-esimo elemento. Scambialo con A[i] */ temp = A[i]; A[i] = A[minIndex]; /* minIndex indice dell’iesimo el. */ A[minIndex] = temp; } return A[k-1]; } Per il calcolo della complessita’ si puo’ osservare quanto segue: i) il ciclo for esterno e’ eseguito k volte; ii) per ogni valore di i, il ciclo interno e’ eseguito n-i volte. Una prima approssimazione del costo dell’algoritmo e’ dunque O(kn), perche’ n-i<n. Una stima piu’ precisa si ottiene sommando i contributi delle diverse iterazioni del ciclo piu’ interno. Si ha: k k(k + 1) c o st o c (n i) ckn - c O kn - k 2 , 2 i1 dove la costante c tiene conto delle istruzioni eseguite nel ciclo for piu’ interno, delle inizializzazioni ecc. 2. Il tipo astratto DoppioStack e’ consente le seguenti operazioni: - headPush(): inserimento in testa. tailPush(): inserimento in coda. headPop(): rimozione e restituzione dell’elemento in testa. - tailPop(): rimozione e restituzione dell’ elemento in testa. - top(): restituzione (senza rimozione) dell’elemento in testa. - bottom():restituzione (senza rimozione) dell’elemento in coda. Si implementi in Java tale tipo per oggetti generici, usando LinkedList e garantendo l’aderenza del tipo implementato a quello astratto. Sol. si veda la soluzione dell’esercizio n. 3 della parte 2. - 3. Considerato l’ADT BST dalle classi BSTNode e BSTTree cosi’ fatte: public class BSTNode { private Comparable key; BSTNode left, right; /* figli */ /* Costruttori */ public void visit() { key.visit(); } public boolean isLeaf() {…} public Comparable key() {return key;} } public class BSTTree { private BSTNode root; /* altre variabili di classe */ /* Costruttori */ public root() {return root;} public void insert(Comparable el) {…} public void delete(Comparable el){…} public BSTNode search (Comparable el) {…} /* altri metodi */ } Scrivere un metodo BSTNode max() della classe BSTTree, che restituisce il nodo avente chiave massima. Sol. il nodo in questione e’ quello piu’ a destra. Dunque: public BSTNode max() { BSTNode temp = root(); if (temp = null) /* Albero vuoto */ return temp; while (temp.right != null) temp = temp.right; return temp; } 4. Si consideri un heap minimale a chiavi intere H dotato delle consuete operazioni insert(int k), deleteMin(), getMin(). Mostrare come esso puo’ essere usato per ordinare un array A di n interi in tempo asintoticamente ottimo. Sol. E’ sufficiente inserire gli elementi di A in H e poi eseguire n estrazioni del minimo. Cio’ puo’ essere ottenuto nel modo seguente: for (i=0; i<n; i++) H.insert(A[i]); for (i=0; i<n; i++) A[i] = H.deleteMin(); Si osservi che il costo di questo algoritmo e’ O(nlog2n). Il motivo e’ che ciascun inserimento/cancellazione ha costo O(log2n) nel caso peggiore e abbiamo n inserimenti ed n cancellazioni. 5. Si scrivano le classi necessarie a implementare grafi non diretti, con pesi interi sugli archi, con al piu’ N nodi e rappresentati mediante matrice di adiacenza. La classe che rappresenta il grafo deve implementare, tra le altre, le operazioni di inserimento e rimozione di archi. Sol. si definisce innanzi tutto una classe Arco, che rappresenta il generico arco tra due nodi: public class Arco { String etichetta; /* Es.: per assegnare identificatori agli archi */ int peso; public Arco(String e, int p) { etichetta = e; peso = p; } public Arco() { eitchetta = null; peso = 0; } } A questo punto possiamo definire la classe Grafo: public Grafo { private Arco[][] mioGrafo; private static final int N = 100; /* No. Max. di vertici */ /* Costruttore */ public Grafo() { mioGrafo = new Arco[N][N]; /* Inizialmente il grafo e’ vuoto */ for (int i=0; i<N ; i++) for (int j=0; j<N; j++) A[i][j] = null; } /* Metodi */ public void insert(Arco a, int i, int j) { /* Inserisce arco tra vertici di indici i e j */ mioGrafo[i][j] = a; return; } public Arco remove(int i, int j) { /* Rimuove e restituisce l’arco tra i vertici i e j */ Arco temp = null; temp = mioGrafo[i][j]; mioGrafo[i][j] = null; return temp; } /* Altri metodi */ } /* Fine della classe Grafo */