Cours3

publicité
Algorithme et structure de
données
IUP1 Miage
Structure de donnée composée
Une entité qui possède plusieurs attribut (ou
champs)
Exemple :
 Un individu à un nom, un prénom et un
numéro

Une voiture à une marque, une puissance,
une valeur, …
Les Fractions
Une fraction a un numérateur et un dénominateur ;
les attributs sont de type entier
class Fraction {
public int numerateur ;
public int denominateur ;
}
Comment accéder aux attributs ?
class Fraction {
public int numerateur;
public int denominateur;
}
public class Test {
… main(…){
Fraction f = new Fraction();
f.numerateur=13; f.denominateur=21;
S.o.p(f.numerateur/f.denominateur);
}
La classe Fraction
les attributs sont de type entier, leur valeur initiale est un
nombre entier aléatoire (non nul pour le dénominateur !)
class Fraction {
private final int Max=100;
public int numerateur=(int)
(Math.random()*Max);
public int denominateur=(int)
(Math.random()*(Max-1))+1;
}
La classe Fraction
Une fraction est capable de répondre au message
toString() qui retourne une description de la
fraction sous la forme d’une String
"numerateur/denominateur=valeur "
public String toString(){
return
numerateur+"/"+denominateur+"="+numerateur
/(double)denominateur;
}
Comment ce servir da la classe
Fraction ?
public class Test {
… main(…){
Fraction f = new Fraction();
S.o.p(f);
}
> java Test
13/26=0.5
Comment ce servir da la classe
Fraction ?
public class Test {
… main(…){
Fraction f = new Fraction();S.o.p(f);
f.numerateur
= 6 ;
f.denominateur = 2 ;
S.o.p(f);
}
> java Test
71/22=3.227272727272727
6/2=3.0
Un tableau de Fractions
… main(…){
Fraction[] tab=new Fraction[4] ;
for(int i=0;i< tab.length;i++){
tab[i]=new Fraction();
S.o.p(tab[i]);
}
}
Structure de Liste chaînée

Un élément d’une liste possède un attribut valeur
(de type entier) et un attribut suivant de type
élément

C’est bien une définition récursive !

Avantage : le nombre d’éléments est variable et
les éléments sont créés (ou supprimés) à la
demande pendant l’exécution
Élément d’une liste chaînée
class Element {
public int valeur ;
public Element suivant ;
}
Structure de Liste chaînée

Une liste possède un seul attribut tete de type
Element qui représente le premier élément de la
liste

Une Liste est initialement vide (la valeur de
l’attribut tete est null)
class Liste {
public Element tete = null
}
;
Quatre listes chaînées
Construire une liste vide
class Test {
… main(…){
Liste l = new Liste() ;
S.o.p(l);
}
}
> java Test
[]
Ajouter un nouvel élément en tête de la
liste
… main(…){
Liste l= new Liste(); S.o.p(l);
Element e=new Element();
e.valeur=99;e.suivant=null ;
l.tete=e; S.o.p(l);
}
> java Test
[]
[ 99 ]
Ajouter un nouvel élément en tête de la
liste
… main(…){
Liste l= new Liste(); S.o.p(l);
Element e1 = new Element();
e1.valeur=99;e1.suivant=null ;
l.tete=e1;S.o.p(l);
Element e2 = new Element();
e2.valeur=100;e2.suivant=l.tete ;
l.tete=e2;S.o.p(l);
}
> java Test
[]
[ 99 ]
[ 100 99 ]
Ajouter un nouvel élément en tête de la
liste
… main(…){
Liste l= new Liste(); S.o.p(l);
Element e1 = new Element();
e1.valeur=99;e1.suivant=null ;
l.tete=e1;S.o.p(l);
Element e2 = new Element();
e2.valeur=100;e2.suivant=l.tete ;
l.tete=e2;S.o.p(l);
Element e3 = new Element();
e3.valeur=101;e3.suivant=l.tete ;
l.tete=e3;S.o.p(l);
}
> java Test
[]
[ 99 ]
[ 100 99 ]
[ 101 100 99 ]
Ajouter un nouvel élément en tête de la
liste
Ajouter un nouvel élément en tête de la liste
… main(…){
Liste l= new Liste(); S.o.p(l); //l.tete=null
Element e1 = new Element();
e1.valeur=99;e1.suivant=l.tete ;
l.tete=e1;S.o.p(l);
Element e2 = new Element();
e2.valeur=100;e2.suivant=l.tete ;
l.tete=e2;S.o.p(l);
}
> java Test
[]
[ 99 ]
[ 100 99 ]
void ajouterEnTete(Element e)

Méthode qui ajoute un nouvel élément en tête de la liste
(celle qui reçoit le message)
class Liste {
public Element tete = null
;
void ajouterEnTete(Element e){
e.suivant=this.tete ; this.tete=e;
}
}
Créer une liste de 10 éléments …
class Element {
public int valeur = (int) (Math.random()*100);
public Element suivant ;
}
class Test {
… main(…) {
Liste l= new Liste() ; S.o.p(l);
for(int i=0; i<10 ; i++) l.ajouterEnTete(new Element()) ; S.o.p(l);
}
}
> java Test
[]
[ 65 32 66 33 55 51 12 36 11 83 ]
String toString()
Méthode qui retourne une description de la liste (celle qui reçoit le
message) sous la forme d’une String
"[valeurDeTete..valeurDeQueue]"
class Test {
… main(…) {
Liste l = new Liste() ;
for(int i=0;i<10;i++)
l.ajouterEnTete(new Element()) ;
S.o.p(l);
S.o.p(l.toString());
}
}
String toString()
class Liste {
public Element tete = null
;
String toString(){
String s="[ ";
for(Element p=tete;p!=null;p=p.suivant)
s+=p.valeur+" ";
return s+="]";
}
}
Recherche dans une liste
class Test {
… main(…) {
Liste l= new Liste() ;
for(int i=0;i<10;i++) l.ajouterEnTete(new Element());
S.o.p("20 in " + l + " is " + l.estDans(20));
}
}
> java Test
20 in [ 49 34 3 49 56 37 73 67 82 99 ] is false
> java test
20 in [ 16 20 84 5 97 24 26 18 58 84 ] is true
Recherche dans une liste
boolean estDans(int x) {
Element p=tete;
while (p != null && p.valeur != x)
p = p.suivant;
return !(p == null) ;
}
Retirer le premier élément
class Test {
… main(…){
Liste l= new Liste() ;
for(int i=0;i<10;i++){
l.ajouterEnTete(new Element()); }
S.o.p(l);l.retirerEnTete();S.o.p(l);
}
}
> java Test
[ 33 74 44 73 20 29 47 51 11 36 ]
[ 74 44 73 20 29 47 51 11 36 ]
Retirer le premier élément
void retirerEnTete(){
if (! listeVide())
tete=tete.suivant;
}
Suppression de la première occurrence
class Test {
… main(…){
Liste l= new Liste() ;
for(int i=0;i<10;i++) {
l.ajouterEnTete(new Element()); }
S.o.p(l); l.supprimer(20) ; S.o.p(l);
}
}
> java Test
[ 48 71 76 3 13 72 85 0 56 90 ]
[ 48 71 76 3 13 72 85 0 56 90 ]
> java Test
[ 37 7 20 26 6 5 57 80 0 87 ]
[ 37 7 26 6 5 57 80 0 87 ]
Suppression de la première occurrence
de v
void supprimer(int v){
Element p=tete;
if (tete != null){
if (tete.valeur==v) { retirerEnTete();}
else {
while (p.suiv!=null && p.suiv.valeur!=v)
p=p.suiv;
if (p.suiv!=null) p.suiv=p.suiv.suiv;
}
}
}
Suppression de la première occurrence
P
P
Retirer le dernier élément
class Test {
… main(…){
Liste l= new Liste() ;
for(int i=0;i<10;i++){
l.ajouterEnTete(new Element()); }
S.o.p(l);l.retirerEnQueue();S.o.p(l);
}
}
> java Test
[ 33 74 44 73 20 29 47 51 11 36 ]
[ 33 74 44 73 20 29 47 51 11 ]
Retirer le dernier élément
void retirerEnQueue(){
if (! listeVide())
if (tete.suivant==null)
// un seul element
tete=null;
else{ // au moins deux elements
Element p=tete;
while (p.suivant.suivant!=null)
p=p.suivant;
p.suivant=null;
}
}
Ajouter en queue
class Test {
… main(…){
Liste l= new Liste() ;
for(int i=0;i<10;i++) {
l.ajouterEnTete(new Element()); }
S.o.p(l);
l.ajouterEnQueue(new Element());
S.o.p(l);
}
}
> java Test
[ 96 21 38 79 99 6 67 4 78 45 ]
[ 96 21 38 79 99 6 67 4 78 45 33 ]
Ajouter en queue
void ajouterEnQueue(Element e){
Element p=tete;
if (listeVide()) {
e.suivant=this.tete ;
this.tete=e;
}
else { // au moins un element
while (p.suivant!=null) p=p.suivant;
p.suivant=e;
e.suivant=null;
}
}
Insertion d'un élément dans la liste en
maintenant l'ordre croissant
class Test {
… main(…){
Liste l= new Liste() ;
for(int i=0;i<10;i++) l.inserer(new Element());
S.o.p(l);
}
}
> java Test
[ 0 20 38 39 41 58 63 79 92 92 ]
> java Test
[ 3 14 33 36 46 52 62 70 71 73 ]
Insertion d'un élément dans la liste en
maintenant l'ordre croissant
void inserer(Element nouveau) {
int v= nouveau.valeur ;
if (tete == null || tete.valeur > v) {
nouveau.suivant = tete ; tete = nouveau;
}
else { // On recherche la position ou insérer la valeur
Element precurseur = tete;
Element curseur = tete.suivant;
while(curseur != null && curseur.valeur < v) {
precurseur = curseur ; curseur = curseur.suivant;
}
precurseur.suivant = nouveau ;
nouveau.suivant = curseur;
}
}
La classe Personne
Une personne possède :
–
un attribut numero (de type int)
–
un attribut nom (de type String)
–
un attribut suivant (de type Personne)
La classe Personne
class Personne {
public int numero ;
public String nom ;
public Personne suivant ;
public String toString(){
return "("+numero+","+nom+")";
}
}
La classe ListeDePersonnes
class ListeDePersonnes {
public Personne tete = null
;
public String toString(){
String s="[ ";
for(Personne p=tete;p!=null;p=p.suivant)
s+=p.toString()+" ";
return s+="]";
}
}
Liste de Personnes triée sur le numéro
On suppose que la liste est triée par ordre
croissant des numéros de personne
void inserer(Personne p)
Méthode qui ajoute un nouvel élément p dans la
liste (celle qui reçoit ce message) en conservant
l’ordre des numéros
Liste de Personnes triée sur le numéro
class Test {
… main(…){
ListeDePersonnes l = new ListeDePersonnes();
Personne p ;
for(int i=0; i<5 ; i++) {
p=new Personne();
p.numero=(int) (Math.random()*100);
p.nom=Console.readLine("Le Nom ?");
l.inserer(p);
}
S.o.p(l);
}
}
> java Test
[ (17,tutu) (22,toto) (39,titi) (45,tete) (95,tata) ]
void inserer(Personne nouveau)
void inserer(Personne nouveau) {
int v= nouveau.numero ;
// On teste si la liste est vide
if (tete == null || tete.numero > v) {
nouveau.suivant = tete ; tete = nouveau;
}
else { // On recherche la position ou insérer la valeur
Personne precurseur = tete;
Personne curseur = tete.suivant;
while(curseur != null && curseur.numero < v) {
precurseur = curseur;
curseur = curseur.suivant;
}
precurseur.suivant = nouveau;
nouveau.suivant = curseur;
}
}
Liste de Personnes triée sur le nom
On suppose que la liste est triée par ordre
croissant des noms de personne
void inserer2(Personne p)
Méthode qui ajoute un nouvel élément p dans la
liste (celle qui reçoit ce message) en conservant
l’ordre des noms
void inserer2(Personne nouveau)
void inserer2(Personne nouveau) {
String v = nouveau.nom ;
if (tete == null || tete.nom.compareTo(v)>0) {
nouveau.suivant = tete;
tete = nouveau;
}
else { // On recherche la position ou insérer la valeur
Personne precurseur = tete;
Personne curseur = tete.suivant;
while(curseur != null && curseur.nom.compareTo(v)<0) {
precurseur = curseur;
curseur = curseur.suivant;
}
precurseur.suivant = nouveau;
nouveau.suivant = curseur;
}
}
Liste chaînée circulaire

On suppose qu’il existe au moins un élément

Le dernier « pointe » sur le premier

Comment détecter le dernier élément ?
Liste chaînée circulaire
Créer une liste circulaire
e
tete
Créer (construire) une liste circulaire
class ListeCirculaire {
public Element tete
;
public ListeCirculaire(){
Element e = new Element();
tete = e ;
e.suivant = tete ;
}
}
Créer (construire) une liste circulaire
class Test {
… void main(…){
ListeCirculaire lc=new ListeCirculaire();
S.o.p(lc);
}
}
> java Test
[ 83 ]
void ajouterEnTete(Element e)
class Test {
… void main(…){
ListeCirculaire lc=new ListeCirculaire();
for(int i=0; i<5 ; i++)
lc.ajouterEnTete(new Element());
S.o.p(lc);
}
}
> java Test
[ 68 61 26 12 92 94 ]
void ajouterEnTete(Element e)
class ListeCirculaire {
public Element tete ;
public ListeCirculaire(){…}
public Element dernierElement(){
Element p=tete;while(p.suivant!=tete) p=p.suivant;
return p;
}
public void ajouterEnTete(Element e){
Element d=this.dernierElement();
e.suivant=this.tete ; this.tete=e; d.suivant=tete;
}
Liste chaînée circulaire
(version optimisée)
tete
queue
void ajouterEnTete(Element e)
(version optimisée)
class ListeCirculaire {
public Element tete ;
public Element queue ;
public ListeCirculaire(){…}
public void ajouterEnTete(Element e){
e.suivant=this.tete ; this.tete=e;
queue.suivant=tete;
}
}
Créer une liste circulaire
(version optimisée)
e
tete
queue
Version optimisée du constructeur
public ListeCirculaire()
class ListeCirculaire {
public Element tete ;
public Element queue ;
public ListeCirculaire(){
Element e=new Element();
tete=e ; e.suivant=tete;
queue=e;
}
public void ajouterEnTete(Element e){…}
}
void retirerEnQueue()
class Test {
… void main(…){
ListeCirculaire lc=new ListeCirculaire();
for(int i=0; i<5 ; i++)
lc.ajouterEnTete(new Element());
S.o.p(lc);
lc.retirerEnQueue() ; S.o.p(lc);
}
}
> java Test
[ 90 88 88 28 15 16 ]
[ 90 88 88 28 15 ]
void retirerEnQueue()
void retirerEnQueue(){
if (! listeVide())
if (tete.suivant==null) // un seul element
tete=null;
else{ // au moins deux elements
Element p=tete;
while (p.suivant.suivant!=tete) p=p.suivant;
p.suivant=tete;
queue=p;
}
}
Structure de Pile :
dernier-entré-premier-sorti

Une pile est une liste linéaire particulière : on ne
peut accéder qu'au dernier élément, que l'on
appelle le sommet de la pile

Dans une pile, il est impossible d'accéder à un
élément au « milieu » !

Les piles sont aussi appelées structures LIFO
pour Last In First Out
Structure de Pile
Une Pile est une liste chaînée particulière !



On peut lire uniquement la valeur de l’élément de
tête (on dit le sommet)
On peut empiler : ajouter un élément en tête
On peut dépiler : retirer l’élément en tête
Dépiler puis Empiler …
Définir la classe Pile

Écrire une méthode boolean pileVide() qui
indique si la pile est vide

Écrire une méthode int getSommet() qui retourne
(s’il existe !) la valeur au sommet de la pile

Écrire une méthode void empiler(Element e) qui
ajouter un nouvel élément e en tête de la pile (celle qui
reçoit ce message)

Écrire une méthode void depiler() qui supprime
(s’il existe !) le sommet de la pile
boolean pileVide()
class Pile {
public Element tete = null
;
boolean pileVide() {return tete == null ; }
}
int getSommet()
class Pile {
public Element tete = null
;
public int getSommet(){
int r=0;
if (pileVide()) {
S.o.p("ERREUR : ACCES PILE VIDE");
System.exit(0);}
else r=tete.valeur;
return r;
}
}
void empiler(Element e)
public class Pile {
public Element tete = null
;
public void empiler(Element e){
e.suivant=tete ; tete=e;
}
}
void empiler(int v)
public class Pile {
public Element tete = null
;
public void empiler(int v){
Element e= new Element();
e.valeur=v ;
e.suivant=tete ; tete=e;
}
}
void depiler()
class Pile {
public Element tete = null
public void depiler(){
if (! pileVide()) {
tete=tete.suivant;}
}
}
;
Structure de File :
premier-entré-premier-sorti

Une file est une liste linéaire particulière

on ne peut ajouter qu'en tête de liste, consulter qu'en
queue de liste, et supprimer qu'en queue de liste

La tête de la liste devient la queue de la file
La queue de la liste devient la tête de la file


Les files sont appelées structures FIFO pour First In First
Out
Structure de File :
void enfiler(Element e)
Ajouter un nouvel élément e en queue de file (en fait en tête de la liste)
class Test {
… void main(…){
File f= new File() ; S.o.p(f);
Element e= new Element() ; e.valeur=99;
f.enFiler(e) ; S.o.p(f);
e= new Element() ; e.valeur=100;
f.enFiler(e) ; S.o.p(f);
}
}
>
[
[
[
java Test
]
99 ]
100 99 ]
Structure de File :
void enfiler(Element e)
Ajouter un nouvel élément e en queue de file (en
fait en tête de la liste)
public void enfiler(Element e){
e.suivant=tete ; tete=e;
}
Structure de File :
void enfiler(int v)
Ajouter un nouvel élément e en queue de file (en fait en tête de la liste)
de valeur v
class Test {
… void main(…){
File f = new File() ; S.o.p(f);
for(int i=0;i<5;i++) f.enFiler(i);
S.o.p(f);
}
}

java Test
[ ]
[ 4 3 2 1 0 ]
Structure de File :
void enfiler(int v)
Ajouter un nouvel élément en queue de file (en fait
en tête de la liste) de valeur v
void enfiler(int v){
Element e = new Element() ;
e.valeur=v ;
e.suivant=tete ; tete=e;
}
Structure de File :
void defiler()
Supprimer l’élément en tête de file (en queue de la liste)
class Test {
... void main(...){
File f= new File() ; S.o.p(f);
for(int i=0;i<5;i++) f.enFiler(i);
S.o.p(f);
f.deFiler();f.deFiler();f.deFiler();
S.o.p(f);
}
}
>
[
[
[
java Test
]
4 3 2 1 0 ]
4 3 ]
Structure de File :
void defiler()
Supprimer (s’il existe !) l’élément en tête de file (en fait en queue de la
liste)
void deFiler(){
if (! fileVide())
if (tete.suivant==null) // un seul element
tete=null;
else { // au moins deux elements
Element p=tete;
while (p.suivant.suivant!=null)
p=p.suivant;
p.suivant=null;
}
}
Structure de File :
int getProchainSorti()
Retourner la valeur en tête de file (ie. la valeur du prochain élément à
sortir de la file)
class Test {
... void main(...){
File f= new File() ; S.o.p(f);
for(int i=0;i<5;i++) f.enFiler(i);
S.o.p(f);
S.o.p(f.getProchainSorti());
}
}
> java Test
[ ]
[ 4 3 2 1 0 ]
0
Structure de File :
int getProchainSorti()
Retourner (s’il existe !) la valeur en tête de file (ie. la valeur du prochain
élément à sortir de la file) et donc la queue de la liste !
int getProchainSorti(){
int r=0 ; Element p=tete ;
if (fileVide()) {
System.out.println("ERREUR : FILE VIDE");
System.exit(0);}
else
do {
r=p.valeur;
p=p.suivant;
} while (p!=null);
return r;
}
Arbre binaire

Structure importante en informatique

Organisation des fichiers dans les systèmes
d'exploitation
représentation des programmes traités par un ordinateur
d'une table des matières,
d'un questionnaire,
d'un arbre généalogique,
permet d'écrire des algorithmes très performants





Encore une structure récursive !
-
-
Un arbre est vide
Un arbre a un seul nœud
Un arbre a un sous-arbre gauche
Un arbre a un sous-arbre droit
Un arbre a deux sous-arbres droit et gauche
Arbre binaire
Les Nœuds de l’arbre !
class Noeud {
public int valeur;
public Noeud gauche ;
public Noeud droit ;
}
Un arbre binaire
class ArbreBinaire {
public Noeud racine
;
boolean arbreVide(){
return this.racine==null;
}
}
Comment créer un arbre ?
class Test {
… void main(…){
ArbreBinaire a=new ArbreBinaire() ;
S.o.p(a);
Noeud n=new Noeud(); n.valeur=8 ;
a.racine=n ; S.o.p(a);
n=new Noeud() ; n.valeur=7;
a.racine.droit=n ; S.o.p(a);
n=new Noeud() ; n.valeur=4;
a.racine.gauche=n ; S.o.p(a);
}
}
Un premier arbre !
> java Test
v
-------------------------------v
8
v
-------------------------------v
7
v
8
v
------------------------------v
7
v
8
v
4
v
String toString() dans la classe
ArbreBinaire
class ArbreBinaire {
public Noeud racine
;
public String toString(){
String s="";
if (racine==null) s+="v\n";
else s+=racine.toString(0);
return s+=“------------------\n";
}
}
String toString(int) dans la
classe Noeud
String toString(int indent){
final int TAB=3;
String s="";
if (droit==null){
for(int i=0;i<indent+TAB;i++) s+=" ";s+="v\n";
}
else s+=droit.toString(indent+TAB);
for(int i=0;i<indent;i++) s+=" ";s+=valeur+"\n";
if (gauche==null){
for(int i=0;i<indent+TAB;i++) s+=" ";s+="v\n";
}
else s+=gauche.toString(indent+TAB);
return s;
}
Void ajouterRacineGauche(Noeud)
class Test{
… void main(…){
ArbreBinaire a=new ArbreBinaire() ;
Noeud n=new Noeud(); n.valeur=8 ;
a.racine=n ; S.o.p(a);
a.ajouterRacineGauche(new Noeud());
S.o.p(a);
a.ajouterRacineDroit(new Noeud());
S.o.p(a);
}
}
Void ajouterRacineGauche(Noeud)
> java Test
v
8
v
----------------------------v
68
v
8
v
----------------------------v
68
v
8
v
33
v
-----------------------------
int nombreNoeud()dans la classe
ArbreBinaire
class ArbreBinaire {
public Noeud racine
;
public int nombreNoeud(){
if (racine==null) return 0;
else return racine.nombreNoeud();
}
}
int nombreNoeud()dans la classe
Noeud
public int nombreNoeud(){
int d , g ;
if (droit==null) d=0 ;
else d=droit.nombreNoeud();
if (gauche==null) g=0 ;
else g=gauche.nombreNoeud();
return 1+d+g;
}
Arbre Binaire Ordonnée

Le domaine des éléments doit être totalement
ordonné
Pour un nœud n donné,
 toutes les valeurs stockées dans le sous-arbre
gauche sont inférieures à celle de n

toutes les valeurs stockées dans le sous-arbre
droit sont supérieures à celle de n
Arbre Binaire Ordonnée
class Test{
… void main(…){
ArbreBinaire a=new ArbreBinaire();
a.inserer(1) ; S.o.p(a);
a.inserer(5) ; S.o.p(a);
a.inserer(2) ; S.o.p(a);
}
}
void inserer(int) dans la classe
ArbreBinaire
> java Test
v
1
v
----------------------------v
5
v
1
v
----------------------------v
5
v
2
v
1
v
a.inserer(4) ; S.o.p(a) ;
a.inserer(3) ; S.o.p(a) ;
v
5
v
2
v
1
v
----------------------------v
5
v
4
v
2
v
1
v
----------------------------v
5
v
4
v
3
v
2
v
1
v
void inserer(int) dans la classe
ArbreBinaire
class ArbreBinaire {
public Noeud racine ;
void inserer(int v){
if (racine==null) {
racine = new Noeud();
racine.valeur=v ;
}
else racine.inserer(v);
}
}
void inserer(int) dans la classe
Noeud
void inserer(int v){
if (valeur<=v) {
if (droit==null){
droit = new Noeud(); droit.valeur=v ;}
else droit.inserer(v);
}
else { // valeur>v
if (gauche==null){
gauche = new Noeud(); gauche.valeur=v ;}
else gauche.inserer(v);
}
}
Téléchargement