Examen final - solution

1 Flots compressés

Partie 1

Le patron Decorator, qui nous permet de décorer un flot d'entrée quelconque pour lui ajouter la possibilité de décompresser un flot compressé.

Partie 2

public final class RLEInputStream extends InputStream {
    private InputStream stream;
    private int value = -1;
    private int count = 0;

    public RLEInputStream(InputStream stream) {
        this.stream = stream;
    }

    @Override
    public int read() throws IOException {
        if (count-- > 0) {
            return value;
        } else {
            count = stream.read();
            if (count == -1)
                return -1; // end of stream reached
            value = stream.read();
            if (value == -1)
                throw new IOException("malformed RLE stream: "
                                      + "no value found for count "
                                      + count);
            return value;
        }
    }

    @Override
    public void close() throws IOException {
        stream.close();
    }
}

2 Itérateurs

Partie 1

Il s'agit du patron Composite. On le voit au fait que AddingIterator est lui-aussi un itérateur et qu'il compose le comportment de deux autres itérateurs.

Partie 2

Oui, il est possible et même facile de construire l'itérateur iSum3, de la manière suivante :

Iterator<Integer> iSum3 = new AddingIterator(iSum, i3);

Partie 3

10, 11, 12.

Partie 4

public final class AddingIterator implements Iterator<Integer> {
    private final Iterator<Integer> i1, i2;

    public AddingIterator(Iterator<Integer> i1,
                          Iterator<Integer> i2) {
        this.i1 = i1;
        this.i2 = i2;
    }

    @Override
    public boolean hasNext() {
        return i1.hasNext() && i2.hasNext();
    }

    @Override
    public Integer next() {
        return i1.next() + i2.next();
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException();
    }
}

Partie 5

On pourrait utiliser le patron Strategy pour représenter l'opération de combinaison au moyen d'un objet implémentant une interface dotée d'une seule méthode, la méthode de combinaison.

3 Vecteurs creux

Partie 1

Il faut bien penser à copier la table nonZeroEntries reçue en argument, faute de quoi la classe SparseVector n'est pas immutable.

public SparseVector(Map<Integer, Double> nonZeroEntries, int size){
    if (size < 0)
        throw new IllegalArgumentException("invalid size: "
                                           + size
                                           + " (must be >= 0)");
    for (int index: nonZeroEntries.keySet()) {
        if (! (0 <= index && index < size))
            throw new IllegalArgumentException("invalid index: "
                                               + index
                                               +" (must be in [0;"
                                               + (size - 1) +"]");
    }
    this.nonZeroEntries = new HashMap<>(nonZeroEntries);
    this.size = size;
}

Partie 2

public int size() {
    return size;
}

Partie 3

public double get(int index) {
    if (! (0 <= index && index < size))
        throw new IllegalArgumentException("invalid index: "
                                           + index
                                           +" (must be in [0;"
                                           + (size - 1) +"]");
    Double maybeEntry = nonZeroEntries.get(index);
    return maybeEntry == null ? 0 : maybeEntry;
}

Il est également possible d'utiliser containsKey pour vérifier la présence de l'élément d'index donné dans la table des éléments non nuls, plutôt que de tirer parti du fait que get retourne null dans ce cas, comme c'est fait ici.

Michel Schinz – 2013-05-31 15:20