ESERCIZI 4

  1.  [Alberi]
    Definire una classe Tree<V> per rappresentare alberi tali che ad ogni nodo è associato un valore di tipo generico V. La classe deve definire una classe annidata statica Tree.Node<V> per rappresentare i nodi dell'albero. Tale classe deve essere pubblica e deve avere solamente due metodi pubblici (può avere altri metodi o costruttori ma devono essere privati):
    • public V getValue()   ritorna il valore associato al nodo
    • public void setValue(V v)   associa il valore v al nodo.
    La classe Tree<V> deve definire i seguenti costruttore e metodi.
    • Un costruttore che prende come parametro un valore v e crea un albero composto dalla sola radice a cui è associato il valore v.
    • Un metodo che ritorna la radice dell'albero (di tipo Tree.Node<V>).
    • Un metodo che prende in input un nodo u e ritorna true se e solo se il nodo u appartiene all'albero.
    • Un metodo che prende in input un nodo u e ritorna il nodo padre di u (se u è la radice ritorna null). Se u non appartiene all'albero lancia un'eccezione IllegalArgumentException.
    • Un metodo Set<Tree.Node<V>> getChildren(Tree.Node<V> u) che ritorna una vista non modificabile dell'insieme dei nodi figli di u. Se u non appartiene all'albero lancia un'eccezione IllegalArgumentException.
    • Un metodo Tree.Node<V> addChild(Tree.Node<V> u, V v) che aggiunge all'albero un nuovo nodo come figlio del nodo u, con valore associato v, e ritorna il nuovo nodo. Se u non appartiene all'albero lancia un'eccezione IllegalArgumentException.
    • La classe deve implementare l'interfaccia Iterable<Tree.Node<V>> per iterare sui nodi dell'albero. L'iteratore ritornato non deve supportare il metodo remove().

  2. [Pred_Succ]
    Scrivere un metodo statico generico che preso in input un insieme di tipo Set<...>, parametrizzato in modo che gli elementi implementino l'interfaccia Comparable, e un elemento x, ritorna sia il predecessore che il successore di x nell'insieme. Definire un opportuno tipo generico per rappresentare l'output del metodo. Il successore di x è il più piccolo elemento dell'insieme che è strettamente maggiore di x, se x è maggiore od uguale al massimo dell'insieme allora è null. Il predecessore di x è il più grande elemento dell'insieme che è strettamente minore di x, se x è minore od uguale al minimo dell'insieme allora è null.

  3. [Errori_1]
    Il seguente codice Java contiene uno o più errori. Trovare gli errori e spiegarli, indicando anche per ogni errore se si verifica in compilazione o durante l'esecuzione.
    import java.util.*;

    public class Test {
    public static void main(String[] args) {
    List<List<String>> sLL = new ArrayList<List<String>>();
    sLL.add(new LinkedList<String>());
    LinkedList<String> linked = sLL.get(0);
    ArrayList<String>[] lsA = new ArrayList<String>[10];
    List<? extends Comparable<String>> csL;
    csL = sLL.get(0);
    sLL.add(csL);
    }
    }

  4. [Insiemi_disgiunti]
    Per insieme generico (con elementi di tipo E) intendiamo un qualsiasi tipo che implementa la seguente interfaccia:
    public interface GSet<E> extends Iterable<E> {
    boolean contains(E x); // Ritorna true se x appartiene all'insieme generico
    }
    Ad esempio, una classe che rappresenta un insieme generico di stringhe potrebbe chiamarsi StrGSet e implementare GSet<String>. Si vuole definire una classe generica per gestire insiemi di insiemi generici disgiunti con elementi dello stesso tipo. La classe ha un solo parametro di tipo E che rappresenta il tipo degli elementi degli insiemi generici. La classe deve definire i seguenti costruttori e metodi.
    • Un costruttore (può anche essere quello di default) che costruisce un insieme vuoto.
    • Un metodo che aggiunge un insieme generico all'insieme solo se questo è disgiunto da tutti gli insiemi generici già presenti e ritorna true. Altrimenti ritorna false.
    • Metodi per controllare se un insieme generico appartiene all'insieme e per rimuovere un insieme generico dall'insieme.
    • Un metodo che preso in input un insieme generico s ritorna l'insieme (di tipo Set, creato ex novo) che contiene tutti gli insiemi generici che non sono disgiunti da s.
    • Un metodo che presa in input una collezione (di tipo Collection) di oggetti di un qualsiasi tipo che è un sottotipo di insiemi generici con elementi di tipo E, rimuove dall'insieme ogni insieme generico s che ha intersezione non vuota con qualche insieme della collezione.
    • Un metodo che ritorna in un insieme di tipo Set, creato ex novo, l'unione degli elementi di tutti gli insiemi generici presenti nell'insieme.
    Inoltre, la classe deve implementare l'interfaccia Iterable per iterare sugli insiemi generici dell'insieme.

  5. [Errori_2]
    Il seguente codice Java contiene uno o più errori. Trovare gli errori e spiegarli, indicando anche per ogni errore se si verifica in compilazione o durante l'esecuzione.
    import java.util.*;

    public class Test {
    public static void main(String[] args) {
    Object oggetto = 'a';
    char c1, c2;
    c1 = (char)oggetto;
    c2 = (Character)oggetto;
    Double[] valori = new Double[15];
    Number[] numeri = valori;
    numeri[0] = new Integer(5);
    Set<Integer> insieme = new HashSet<Integer>();
    for (int i = 0 ; i < 10 ; i++) insieme.add(i);
    for (Integer k : insieme)
    if (k % 2 == 0)
    insieme.remove(k);
    valori[1] += insieme.size();
    }
    }

  6. [PrefixFree]
    Consideriamo sequenze generiche di valori rappresentate da classi che implementano la seguente interfaccia:
    public interface Seq<V> {
    V get(int i); //Ritorna l'i-esimo valore della sequenza (la numerazione inizia da 0)
    int length(); //Ritorna la lunghezza della sequenza
    }
    Ad esempio, una classe che rappresenta sequenze di interi potrebbe chiamarsi IntSeq e implementare Seq<Integer>. Si vuole definire una classe generica per gestire insiemi prefix-free di sequenze con valori dello stesso tipo. Un insieme è prefix-free se non ci sono nell'insieme due sequenze che sono l'una il prefisso dell'altra (una sequenza s1 è un prefisso di s2 se per ogni i = 0,1,...,s1.length()-1, s1.get(i) è un valore uguale al valore s2.get(i)). La classe ha un solo parametro di tipo V che rappresenta il tipo dei valori delle sequenze. La classe deve definire i seguenti costruttori e metodi.
    • Un costruttore (può anche essere quello di default) che costruisce un insieme di sequenze vuoto.
    • Un metodo che aggiunge una sequenza all'insieme solo se questa aggiunta non viola la condizione prefix-free dell'insieme e ritorna true. Altrimenti ritorna false.
    • Metodi per controllare se una sequenza appartiene all'insieme e per rimuovere uan sequenza dall'insieme.
    • Un metodo che preso in input un indice i e un valore v (di tipo V) ritorna l'insieme (di tipo Set, creato ex novo) di tutte le sequenze che in posizione i hanno valore v.
    • Un metodo che preso in input una collezione (di tipo Collection) di oggetti di un tipo che è un sottotipo di sequenze di valori di tipo V, rimuove dall'insieme ogni sequenza s che o è un prefisso di una sequenza della collezione o c'è una sequenza della collezione che è un prefisso di s.
    Inoltre, la classe deve implementare l'interfaccia Iterable per iterare sulle sequenze dell'insieme.

  7. [Valore_in _comune]
    Scrivere un metodo generico che presi in input due array ritorna il primo valore del primo array che appare anche nel secondo. Se non ci sono valori in comune ritorna null. Scrivere anche una versione non generica del metodo usando il tipo Object. Esibire un esempio di invocazione dei due metodi che evidenzia il vantaggio offerto dalla versione generica.


  8. [Occorrenze]
    Scrivere un metodo generico che preso in input un array ritorna una mappa, di tipo Map<T,Integer>, che contiene per ogni valore distinto dell'array il numero di occorrenze di quel valore. Esempi:
    ARRAY DI INPUT                  MAPPA DI OUTPUT
    ["A", "BB", "C", "BB", "A"] {("A", 2), ("BB", 2), ("C", 1)}
    [8, 7, 9, 7, 7, null, 9] {(8, 1), (7, 3), (9, 2), (null, 1)}

  9. [Errori_3]
    Il seguente codice Java contiene uno o più errori. Trovare gli errori e spiegarli, indicando anche per ogni errore se si verifica in compilazione o durante l'esecuzione.
    import java.util.*;

    public class Test {
    public static void main(String[] args) {
    List<Long> list = new ArrayList<Long>();
    for (long i = 0 ; i < 10 ; i++) list.add(i);
    for (Long k : list)
    if (k < 100)
    list.remove(k);
    Float[] vals = new Float[10];
    Number[] nums = vals;
    nums[0] = new Integer(7);
    vals[1] += list.size();
    Object o = 23;
    int a = (int)o;
    int b = (Integer)o;
    }
    }

  10. [Dipendenze]
    Si vogliono gestire insiemi di oggetti che hanno relazioni di dipendenza tra loro. Ad esempio, file di configurazione il cui aggiornamento dipende da altri file di configurazione, classi in un programma che dipendono da altre classi, processi la cui esecuzione dipende dall'esecuzione di altri processi. Per garantire la massima generalità si conviene che un tipo T è coinvolto in una relazione di dipendenza se il tipo stesso o un suo supertipo S implementa la seguente interfaccia generica:
    public interface DependingOn<S> {

    boolean directDependsOn(S x); //Ritorna true se questo oggetto dipende direttamente da x o se è uguale a x
    }
    Il metodo dell'interfaccia determina solamente la relazione di dipendenza diretta che, in generale, non è transitiva. Invece, una relazione di dipendenza è per sua natura transitiva, cioè, se x dipende da y e y dipende da z, allora x dipende anche da z. Definire una classe per gestire insiemi di oggetti coinvolti in una relazione di dipendenza (tramite l'interfaccia DependingOn) che permette di ottenere informazioni sulle dipendenze tra gli oggetti dell'insieme che sono conseguenza della transitività. La classe ha un unico parametro di tipo T che rappresenta il tipo degli oggetti coinvolti in una relazione di dipendenza. La classe ha un costruttore che crea un insieme vuoto (potrebbe anche essere quello di default). Poi, deve definire i seguenti metodi.
    • Metodi per aggiungere un elemento e per controllare l'appartenenza di un elemento.
    • Un metodo per rimuovere un elemento x solo se non ci sono altri elementi nell'insieme che dipendono da x. Ritorna true se effettua la rimozione, altrimenti false.
    • Un metodo che prende in input un oggetto x di tipo T e ritorna il sottoinsieme (di tipo Set, creato ex novo) degli elementi dell'insieme che sono direttamente dipendenti da x.
    • Un metodo che prende in input una collezione coll (di tipo Collection con parametro di tipo tale da garantire la massima flessibilità) e ritorna il sottoinsieme degli elementi dell'insieme che sono direttamente dipendenti da qualche elemento della collezione coll.
    • Un metodo che prende in input un oggetto x di tipo T e ritorna il sottoinsieme degli elementi dell'insieme che sono transitivamente dipendenti da x. Un elemento z è transitivamente dipendente da x se esiste un elemento y tale che z dipende direttamente da y e y dipende (transitivamente) da x.
    • La classe deve implementare l'interfaccia Iterable per iterare sugli elementi dell'insieme.

  11. [Conta_valore]
    Scrivere un metodo generico che preso in input un array ritorna il valore più frequente e il suo numero di occorrenze. Definire un opportuno tipo generico per rappresentare l'output del metodo. Ecco alcuni esempi di input e output del metodo:
        INPUT                                        OUTPUT
    {"B", "AB", "A", "B"} ("B", 2)
    {2, 13, 2, 1, 13, 13} (13, 3)