Planche 1

Cours 9
Exploration
Programmation à objets

Jean-Jacques.Levy@inria.fr
http://jeanjacqueslevy.net
tel: 01 39 63 56 89

secrétariat de l'enseignement:
Catherine Bensoussan
cb@lix.polytechnique.fr
Aile 00, LIX
tel: 01 69 33 34 67

http://www.enseignement.polytechnique.fr/informatique/


Planche 2

Plan

  1. Algorithmes gloutons
  2. Programmation dynamique
  3. Enumération d'arborescences
  4. Modularité en Java
  5. Programmation à objets

Planche 3

Exploration


Planche 4

Exemple 1 d'algorithme glouton
Dans un graphe valué non orienté trouver l'arbre de recouvrement minimal. Application: minimiser la longueur de fil pour alimenter un réseau.

Lemme Pour toute partition N et N' de l'ensemble V des noeuds d'un graphe valué non-orienté G = (V, E, d), un arbre de recouvrement minimal contient l'arc de plus petite valeur reliant un noeud de N à un noeud de N'.
Algorithme de Prim:

Exercice 1Implémentation? Complexité?


Planche 5

Exemple 2 d'algorithme glouton


Marche du cavalier sur un échiquier: on choisit le mouvement qui déplace le cavalier sur la case où il attaque le moins de cases.

static int[] x = {2, 1, -1, -2, -2, -1,  1,  2};
static int[] y = {1, 2,  2,  1, -1, -2, -2, -1};

static void marche (int[][] m, int i, int j) {
  int n = 0; int i0, j0;
  do {
    m[i][j] = n++;
    i0 = i; j0 = j;
    int min = Integer.MAX_VALUE;
    for (int d = 0; d < x.length; ++d) {
      int na = nAttaques (m, i0+x[d], j0+y[d]);
      if (min > na) {
        i = i0+x[d]; j = j0+y[d]; 
        min = na;
      }
    }
  } while (i != i0 || j != j0);
}

Planche 6

Marche du cavalier -- suite

static boolean dansEchiquier(int[][] m, int i, int j) {
  return 0 <= i && i < m.length && 0 <= j && j < m[0].length;
}

static int nAttaques (int[][] m, int i, int j) {
  if ( !(dansEchiquier (m, i, j) && m[i][j] == -1) )
    return Integer.MAX_VALUE;
  else {
    int res = 0;
    for (int d = 0; d < x.length; ++d) {
      int i_n = i+x[d], j_n = j+y[d];
      if ( dansEchiquier (m, i_n, j_n) && m[i_n][j_n] == -1 )
        ++res;
    }
    return res;
  }
}

Planche 7

Exemple 1 de programmation dynamique

Plus courts chemins entre tous les noeuds d'un graphe par l'algorithme de Floyd en modifiant l'algorithme de Warshall.
d-1 (i,j)= m(i,j)
dk(i,j) = min { dk-1(i,j),  dk-1(i,k) + dk-1(k,j) }


static Graphe plusCourtsChemins (Graphe g) {
  int n = g.m.length;
  Graphe c = copieGraphe (g);
  for (int k = 0; k < n; ++k)
    for (int i = 0; i < n; ++i)
      for (int j = 0; j < n; ++j)
          c.m[i][j] <- Math.min (c.m[i][j], c.m[i][k] + c.m[k][j]);
  return c;
}

Exercice 2Complexité?

Exercice 3Comparer à l'algorithme de Dijkstra


Planche 8

Exemple 2 de programmation dynamique

Les plus longues sous-séquences communes entre deux chaînes de caractères.
L(i,j)= ì
í
î
1 + L(i-1,j-1) si ui=vj
max (L(i,j-1),L(i-1,j)) sinon.

static int[][] plusLongueSSC (String u, String v) {
  int n = u.length(); int m = v.length();
  int longueur[][] = new int[n][m]; int pred[][] = new int[n][m];
  for (int i = 0; i < n; ++i) longueur[i, 0] = 0;
  for (int j = 0; j < m; ++j) longueur[0, j] = 0;
  for (int i = 1; i < n; ++i)
    for (int j = 1; j < m; ++j)
      if (u.charAt(i) == v.charAt(j)) {
        longueur[i][j] = 1 + longueur[i-1][j-1]; pred[i][j] = 0;
      } else if longueur[i][j-1] > longueur[i-1][j] {
        longueur[i][j] = longueur[i][j-1]; pred[i][j] = 1;
      } else {
        longueur[i][j] = longueur[i-1][j]; pred[i][j] = 2;
      }
   return pred; 

Planche 9

Programmation dynamique -- suite

Exercice 4Complexité de SSC?

Exercice 5Comment implémenter la commande diff du système Unix?

Exercice 6L'associativité de la multiplication de matrices permet de multiplier n matrices M0M1... Mn-1 sans préciser le parenthésage. Pourtant, cela peut faire varier le nombre de multiplications scalaires à effectuer. Donner un algorithme qui utilise la programmation dynamique pour trouver l'ordre optimal.


Planche 10

Exemple 1 d'énumération

Mettre 8 reines sur un échiquier sans qu'elles soient en prise.

static boolean conflit (int i1, int j1, int i2, int j2) {
  return (i1 == i2) || (j1 == j2) ||
         (Math.abs (i1 - i2) == Math.abs (j1 - j2));
}

static boolean compatible (int[] pos, int i, int j) {
  for (int k = 0; k < i; ++k) 
    if (conflit (i, j, k, pos[k])) return false;
  return true;
}

static void reines (int[] pos, int i) {
  if (i >= pos.length) imprimerEchiquier(pos);
  else
    for (int j = 0; j < pos.length; ++j)
      if (compatible (pos, i, j)) { pos[i] = j; reines (pos, i+1); }
}

static void nReines (int n) {
  int[] pos = new int[n];  reines (pos, 0);
}

Planche 11

Exemple 2 d'énumération

Enumération de tous les chemins dans un graphe.

static void enumeration (Graphe g, int x) {
  num[x] = ++id;
  for (int ls = g.succ[x]; ls != null; ls = ls.suivant) {
    int y = ls.val;
    if (num[y] == -1) 
        enumeration(g, y);
  }
  --id; num[k] = -1;
}


Planche 12

Modularité


Planche 13

Programmation à objets

D'où

  modification données modification programme
prog. procédurale changement global changement local
prog. objets changement local changement global

Dans un univers où toutes les données sont proches les unes des autres (i.e. dérivent d'un même modèle), la programmation à objets peut être avantageuse. L'exemple est une boîte à outils graphique, où on ne code principalement que des incréments.


Planche 14

Programmation à objets
Deux autres arguments sont utilisés par les pro-objets:


Planche 15

Exemple de programmation à objets
Dans une classe abstraite, les champs ne sont pas tous définis.


abstract class List {
  abstract boolean empty ();
  abstract List append (List x);
  abstract boolean equals (List x);
  abstract public String toString ();
}
Une instance: les listes vides.


class Nil extends List {
  Nil () { }

  boolean empty () {return true; }

  List append (List x) { return x; }

  boolean equals (List x) { return x.empty(); }

  public String toString () { return ""; }

}

Planche 16

Exemple de programmation à objets
Une autre instance: les listes non vides.


class Cons extends List {
  int hd; List tl;
  Cons (int v, List x) { hd = v; tl = x; }

  boolean empty () {return false; }

  List append (List x) { return new Cons(hd, tl.append(x)); }

  boolean equals (List x) { return 
    !x.empty() && hd == ((Cons)x).hd && tl.equals(((Cons)x).tl);
  }

  public String toString () { 
    return "[" + hd + (tl.empty() ? "]" : "; " + tl.toString() + "]"); 
  }
}
Remarquer la conversion de type obligatoire dans equals. C'est le problème dit du typage des méthodes binaires.

Cf. le cours sur la programmation objet et la modularité en Majeure 1 pour plus de détails.


Planche 17

Exemple de programmation à objets
On peut par la suite se servir de ces fonctions comme suit:

public static void main (String[] args) {
  List x = new Cons (3, new Cons (4, new Nil()));
  List y = new Cons (5, new Nil());
  System.out.println (x.append(y));
  System.out.println (x.equals(y));
  System.out.println (x.equals(x));
}

Planche 18

Autre Exemple de programmation à objets: les termes

abstract class Terme {
  abstract public String toString ();
}

class Add extends Terme {
  Terme a1, a2;
  Add (Terme x, Terme y) {a1 = x; a2 = y; } 
  public String toString () { return "(" + a1 +  " + " + a2 + ")"; }
}

class Mul extends Terme {
  Terme a1, a2;
  Mul (Terme x, Terme y) {a1 = x; a2 = y; } 
  public String toString () { return "(" + a1 +  " * " + a2 + ")"; }
}

class Const extends Terme {
  int valeur;
  Const (int n) { valeur = n; } 
  public String toString () { return valeur + ""; }
}

Planche 19

Terme -- bis
Et on utilise les termes en notation orientée-objet (OO):

public static void main (String[] args) {
  Terme x = new Mul (new Add (new Const(4), new Const(5)),
                     new Const (1));
  System.out.println (x);
}
Pour rajouter de nouveaux constructeurs, il suffit de rajouter de nouvelles sous-classes (programmation incrémentale):

class Var extends Terme {
  String nom;
  Var (String s) { nom = s; } 
  public String toString () { return nom; }
}

class Sub extends Terme {
  Terme a1, a2;
  Sub (Terme x, Terme y) {a1 = x; a2 = y; } 
  public String toString () { return "(" + a1 +  " - " + a2 + ")"; }
}

Planche 20

Terme -- ter
Si on rajoute maintenant une méthode dans les termes, le changement est global.

abstract class Terme {
  abstract int eval (Env e);
  abstract public String toString ();
}

class Add extends Terme {
  Terme a1, a2;
  Add (Terme x, Terme y) {a1 = x; a2 = y; } 
  int eval (Env e) { return a1.eval(e) + a2.eval(e); }
  public String toString () { return "(" + a1 +  " + " + a2 + ")"; }
}

class Mul extends Terme {
  Terme a1, a2;
  Mul (Terme x, Terme y) {a1 = x; a2 = y; } 
  int eval (Env e) { return a1.eval(e) * a2.eval(e); }
  public String toString () { return "(" + a1 +  " * " + a2 + ")"; }
}

Planche 21




class Const extends Terme {
  int valeur;
  Const (int n) { valeur = n; } 
  int eval (Env e) { return valeur; }
  public String toString () { return valeur + ""; }
}

class Var extends Terme {
  String nom;
  Var (String s) { nom = s; } 
  int eval (Env e) { return Env.assoc(nom, e); }
  public String toString () { return nom; }
}

class Sub extends Terme {
  Terme a1, a2;
  Sub (Terme x, Terme y) {a1 = x; a2 = y; } 
  int eval (Env e) { return a1.eval(e) - a2.eval(e); }
  public String toString () { return "(" + a1 +  " - " + a2 + ")"; }
}

Planche 22

Procédural ou Objets?

This document was translated from LATEX by HEVEA.