Cette structure peut être implémentée à l'aide d'un tableau. Voici les principes :
- L'empilement ajoute des éléments à la fin du tableau.
- Le dépilement supprime des éléments de la fin du tableau.
Commençons par un exemple d'utilisation de la classe Stack de Java :
public static void main(String[] args) {
Stack<String> maPile = new Stack<>();
maPile.push("alice");
maPile.push("bob");
maPile.push("charlie");
maPile.push("diana");
System.out.println(maPile.pop());
System.out.println(maPile.pop());
System.out.println(maPile.pop());
System.out.println(maPile.pop());
}
La sortie affiche :
diana
charlie
bob
alice
Cela confirme le comportement LIFO : le dernier élément empilé est le premier dépiler.
Implémentons maintenant une pile personnalisée avec un tableau, en gérant l'ajout et la suppression à la fin du tableau. Voici le code source complet :
public class PilePersonnalisee<E> {
private static final int CAPACITE_INITIALE = 10;
private Object[] stockageInterne;
private int compteurElements;
public PilePersonnalisee() {
this(CAPACITE_INITIALE);
}
public PilePersonnalisee(int capacite) {
if (capacite <= 0) {
throw new IllegalArgumentException("La capacité doit être positive");
}
if (capacite > Integer.MAX_VALUE) {
throw new IllegalArgumentException("La capacité est trop grande");
}
stockageInterne = new Object[capacite];
compteurElements = 0;
}
public boolean estVide() {
return compteurElements == 0;
}
public int obtenirTaille() {
return compteurElements;
}
public E empiler(E valeur) {
if (compteurElements >= stockageInterne.length) {
agrandirStockage();
}
stockageInterne[compteurElements] = valeur;
compteurElements++;
return valeur;
}
public E depiler() {
if (estVide()) {
return null;
}
int positionDernier = compteurElements - 1;
E resultat = obtenirSommet();
compteurElements--;
stockageInterne[positionDernier] = null;
return resultat;
}
public E obtenirSommet() {
if (compteurElements == 0) {
throw new RuntimeException("La pile est vide");
}
return (E) stockageInterne[compteurElements - 1];
}
private void agrandirStockage() {
int ancienneCapacite = stockageInterne.length;
Object[] ancienTableau = stockageInterne;
int nouvelleCapacite = ancienneCapacite * 2;
stockageInterne = new Object[nouvelleCapacite];
for (int index = 0; index < ancienneCapacite; index++) {
stockageInterne[index] = ancienTableau[index];
}
ancienTableau = null;
}
}
Pour cette implémentation, deux aspects sont cruciaux :
- La gestion des opérations à la fin du tableau pour l'empilement et le dépilement.
- L'agrandissement dynamique du tableau lorsque la capacité est atteinte.
Testons notre implémentation avec un exemple :
public static void main(String[] args) {
PilePersonnalisee<String> pileTest = new PilePersonnalisee<>();
pileTest.empiler("premier");
pileTest.empiler("deuxieme");
pileTest.empiler("troisieme");
pileTest.empiler("quatrieme");
System.out.println(pileTest.depiler());
System.out.println(pileTest.depiler());
System.out.println(pileTest.depiler());
System.out.println(pileTest.depiler());
}
Le résultat attendu est :
quatrieme
troisieme
deuxieme
premier