Cours 11 du 10 avril :
Structures récursives: listes chaînées et
Introduction aux types abstraits de données
Listes chaînées
La classe Object
Exemple: tri par insertion
Notion de types abstraits de données
Interface Java pour une Pile
Utilisation des piles: expressions arithmétiques
Listes chaînées
A propos des tableaux:
L'insertion dans un tableau d'un élément peur entraîner un déplacement de tous les
éléments du tableau (O(N) opérations pour un tableau de taille N)
L'accès aux éléments se fait en temps constant (O(1)).
Un tableau est une structure statique avec une taille fixe : (un objet tableau doit avoir
une taille définie en java)
Les listes chaînées permettent d'éviter ces problèmes, on aura:
insertion et suppression en temps constant
Mais l'accès à un élément se fait en temps proportionnel à la taille de la liste
Une liste chaînée peut être définie récursivement par :
« Un liste est soit vide soit un élément suivi d’une liste »
En adaptant cette définition en java, une liste est soit null soit un Noeud. Un Noeud est
composé d’un Item suivi d’une référence vers un Noeud (ou cellule):
class Noeud {
Object item;
Noeud suivant;
public Noeud(Object o) {
item=o;
suivant=null;
}
public Noeud(Object o, Noeud n){
item=o;
suivant=n;
}
}
Notons que si une liste vide est représentée par null, pour accéder à un élément, il faut tester
au préalable que la liste est différente de null. Aussi, il peut être intéressant de considérer
qu’une liste contient au moins un noeud, dans ce cas la valeur de l’item de ce nœud n’est pas
pris en compte et le premier élément la liste (si elle est non vide) est l’item du nœud suivant.
La classe Object
Une liste (comme un tableau) peut être définie pour n’importe quelle classe. Plutôt que de
redéfinir des listes pour chaque classe, on peut vouloir définir des listes pouvant contenir
n’importe quel objet java.
Pour cela, on peut utiliser la classe Object (on a déjà rencontré cette classe à propos de la
méthode toString qui permet de représenté comme chaîne de caractère n’importe quel
objet) ; cette classe permet est dans une certaine mesure universelle elle peut correspondre à
n’importe quel objet. Plus précisément :
Object: tout objet peut être considéré comme étant de la classe Object, on récupère
l'objet avec son type par un forçage de type:
Type x=new Type();
Object ob=x;
Type y=(Type)ob;
Attention, le forçage de type : (Type) est nécessaire.
x
Type
ob
y
x
Type
ob
x
Type
item
suivant
item
suivant
suivant
Java est un langage typé qui vérifie la compatibilité entre les types à la compilation.
Au moment de la compilation, le compilateur vérifie le typage, pour cela à partir des
déclarations des variables et des types il est capable de déterminer le type de n’importe
quelle expression et de vérifier que le typage est correct.
Dans l’exemple précédent, le compilateur sait que x est du type Type et que ob est
du type Object. Cela signifie qu’il sait que x contient une référence sur un objet de
type Type et x une référence de type Object. Comme Object est compatible avec
n’importe quel type, x peut être une référence sur un objet de n’importe quel type.
Il n’y a pas de problème ici parce que tout ce qui est possible avec un Object est
possible avec n’importe quel objet (tous les objets ont, au moins, les propriétés des
Object). Aussi ob=x ne pose pas de problème : x est une référence sur un objet
Type et ob (déclaré comme variable de type Object) va référencer cet objet.
Par contre, y=ob pose un problème : pour le compilateur, ob est une référence sur un
Object (le compilateur ne regardant que les déclarations ne sait pas qu’ici, en fait,
ob est une référence sur un Type) alors que y doit être une référence sur un Type. Le
compilateur ne peut pas accepter (comme telle) cette affectation car tout Object ne
peut pas être considéré comme un Type. On peut le vérifier sur l’exemple suivant, si
on a :
class Type{public int i ; public int j}
class X{double d ;}
Alors, pour :
Object obbis=new X() ;
y=obbis ;
Que peut signifier y.i ? Une expression y.i n’a ici pas de sens alors que dans
l’exemple précédent elle ne posait pas de problème puisque ob était bien une
référence vers un Type.
Aussi, il faut explicitement écrire y=(Type)ob ; qui indique au compilateur que l’on
affirme qu’à ce moment ob référence un objet du type Type. Dans ce cas, il y aura
une vérification qu’au moment de l’exécution de cette affectation ob référence bien un
Type
i :
j :
d :
:
X
obbis
y
Type
i :
j :
d :
:
X
objet de type Type (Si ce n’est pas le cas une exception (=erreur) sera générée qui
provoquera l’arrêt du programme).
En réalité, cet exemple est un exemple de la notion d’héritage en Java. On peut dans le
langage définir des classes qui héritent d’autres classes. Si X hérite de Y alors X a au
moins toutes les caractéristiques (et donc au moins les données membres) de Y plus
éventuellement d’autres, dans ce sens un objet de X peut toujours être considéré
comme un objet de Y (mais pas le contraire puisque Y peut avoir moins de propriétés
que X). Une autre formulation de ce qui précède est que toute classe de java hérite de
la classe Object.
Pour les types primitifs (int, char etc…) il existe des classes correspondantes qui
permettent de passer d'un type primitif à un type référence, par exemple à int
correspond la classe Integer :
int k=100;
Integer j,i=new Integer(100);
Object ob=i;
j=i;
k=k+i.intValue();
k=k+j;
(la plupart du temps ces conversions sont implicites)
Exemple de liste circulaire:
(Cet exemple n’a pas été traité pendant le cours)
On a une ronde avec N personnes, on fait sortir de la ronde la M-ième personne sur la ronde et
on recommence jusqu'à ce qu'il n'y ait plus qu'une personne.
Pour cela on définit une classe ListeCirculaireInt qui représente une liste circulaire
d’entiers. On notera que les entiers sont en fait représentés par des Integer (type référence).
class Noeud {
Object item;
Noeud suivant;
public Noeud(Object o) {
item=o;
suivant=null;
}
public Noeud(Object o, Noeud n){
item=o;
suivant=n;
}
}
class ListeCirculaireInt{
private Noeud cur;
public int val(){
return (Integer)cur.item;
}
public ListeCirculaireInt(){
cur=null;
}
public void suivant(){
if(cur!=null)cur=cur.suivant;
}
public boolean estSingleton(){
if(cur!=null) return cur.suivant==cur;
else return false;
}
public void afficher(){
if(cur==null)return;
Noeud tmp=cur;
do{
System.out.print(tmp.item+" ");
tmp=tmp.suivant;
}while (tmp!=cur);
System.out.println();
}
public void inserer(int val){
Noeud x=new Noeud(new Integer(val));
if(cur==null){cur=x; cur.suivant=cur;} else
{x.suivant=cur.suivant;cur.suivant=x;}
}
public void ajouter(int val){
inserer(val);
suivant();
}
public void supprimer(){
if (cur!=null)cur.suivant=cur.suivant.suivant;
}
}
et le programme:
class Josephe{
public static void main(String[] args) {
// N est le premier argument (nombre de participants)
// M le deuxième paramètre (élimination du M-ième
int N=Integer.parseInt(args[0]);
int M=Integer.parseInt(args[1]);
ListeCirculaireInt l=new ListeCirculaireInt();
for (int i = 1; i <= N; i++) {
l.ajouter(i);
}
l.suivant();
l.afficher();
while(!l.estSingleton()){
for (int i = 1; i <= M; i++)
l.suivant();
System.out.println("élément supprimé "+l.val());
1 / 18 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !