Strutture di Dati Dinamiche in Java – Una Guida Pratica

Woman using laptop on sofa, surrounded by programming books, learning coding.

Introduzione

Nella programmazione, le strutture di dati sono fondamentali per organizzare e gestire informazioni in modo efficiente. Tra queste, le strutture di dati dinamiche giocano un ruolo cruciale, specialmente quando la quantità di dati da gestire non è nota in anticipo. A differenza degli array statici, le strutture dinamiche possono crescere o ridursi durante l’esecuzione del programma, offrendo una maggiore flessibilità.

In questo articolo, esploreremo alcune delle strutture di dati dinamiche più comuni in Java, come VectorStack (pila) e Queue (coda). Vedremo come implementarle e come utilizzarle in scenari pratici, come la gestione di una rubrica telefonica o la simulazione di operazioni di undo/redo in un’applicazione. Alla fine di questa lezione, avrai una solida comprensione di come utilizzare queste strutture per rendere i tuoi programmi più efficienti e flessibili.


Array Dinamici e la Classe Vector

In Java, la classe Vector è una delle strutture di dati dinamiche più utilizzate. A differenza degli array statici, un Vector può crescere o ridursi automaticamente, rendendolo ideale per situazioni in cui non si conosce in anticipo il numero di elementi da memorizzare.

Esempio di utilizzo di Vector:

Vector<String> v = new Vector<>(); v.addElement("Elemento 1"); v.addElement("Elemento 2"); v.removeElementAt(0); // Rimuove il primo elemento

In questo esempio, abbiamo creato un Vector di stringhe e aggiunto due elementi. Successivamente, abbiamo rimosso il primo elemento. La flessibilità del Vector lo rende adatto per gestire collezioni di dati che cambiano frequentemente.

Gestione di un Poligono con Vector

Un esempio pratico di utilizzo di Vector è la gestione dei vertici di un poligono. Ogni vertice può essere rappresentato da un oggetto della classe Punto, che contiene coordinate x e y.

class Punto { private int x, y; public Punto(int x, int y) { this.x = x; this.y = y; } public String toString() { return "x = " + x + ", y = " + y; } } class Poligono { private Vector<Punto> vertici; public Poligono() { vertici = new Vector<>(); } public void aggiungiVertice(Punto p) { vertici.addElement(p); } public void rimuoviVertice(int index) { vertici.removeElementAt(index); } public void stampaVertici() { for (int i = 0; i < vertici.size(); i++) { System.out.println(vertici.elementAt(i)); } } }

In questo esempio, la classe Poligono utilizza un Vector per memorizzare i vertici. I metodi aggiungiVertice e rimuoviVertice permettono di gestire dinamicamente i vertici del poligono.

Rubrica Telefonica con Vector

Un altro esempio pratico è la gestione di una rubrica telefonica. Ogni contatto può essere rappresentato da un oggetto della classe Contatto, che contiene un nome e un numero di telefono.

class Contatto { private String nome; private String telefono; public Contatto(String nome, String telefono) { this.nome = nome; this.telefono = telefono; } public String toString() { return nome + ": " + telefono; } } class Rubrica { private Vector<Contatto> contatti; public Rubrica() { contatti = new Vector<>(); } public void aggiungiContatto(Contatto c) { contatti.addElement(c); } public void rimuoviContatto(int index) { contatti.removeElementAt(index); } public void visualizzaContatti() { for (int i = 0; i < contatti.size(); i++) { System.out.println(contatti.elementAt(i)); } } }

In questo caso, la classe Rubrica utilizza un Vector per memorizzare i contatti. I metodi aggiungiContatto e rimuoviContatto permettono di gestire dinamicamente la rubrica.

Strutture di Dati a Pila (Stack)

Una pila è una struttura di dati dinamica che segue il principio LIFO (Last In, First Out). Gli elementi vengono aggiunti e rimossi dalla cima della pila. Le operazioni principali sono:

  • Push: Aggiunge un elemento in cima alla pila.
  • Pop: Rimuove l’elemento in cima alla pila.
  • Peek: Restituisce l’elemento in cima senza rimuoverlo.

Esempio di implementazione di una pila in Java:

import java.util.Stack; public class EsempioPila { public static void main(String[] args) { Stack<Integer> pila = new Stack<>(); pila.push(10); pila.push(20); pila.push(30); System.out.println("Elemento in cima: " + pila.peek()); System.out.println("Elemento rimosso: " + pila.pop()); System.out.println("Nuovo elemento in cima: " + pila.peek()); } }

In questo esempio, abbiamo creato una pila di interi e aggiunto alcuni elementi. Successivamente, abbiamo rimosso l’elemento in cima e visualizzato il nuovo elemento in cima.

Strutture di Dati a Coda (Queue)

Una coda è una struttura di dati dinamica che segue il principio FIFO (First In, First Out). Gli elementi vengono aggiunti alla fine della coda e rimossi dall’inizio. Le operazioni principali sono:

  • Enqueue: Aggiunge un elemento alla fine della coda.
  • Dequeue: Rimuove l’elemento all’inizio della coda.
  • Peek: Restituisce l’elemento all’inizio senza rimuoverlo.

Esempio di implementazione di una coda in Java:

import java.util.LinkedList; import java.util.Queue; public class EsempioCoda { public static void main(String[] args) { Queue<Integer> coda = new LinkedList<>(); coda.add(10); coda.add(20); coda.add(30); System.out.println("Elemento in testa: " + coda.peek()); System.out.println("Elemento rimosso: " + coda.poll()); System.out.println("La coda è vuota? " + coda.isEmpty()); } }

In questo esempio, abbiamo creato una coda di interi e aggiunto alcuni elementi. Successivamente, abbiamo rimosso l’elemento all’inizio della coda e verificato se la coda è vuota.


FAQ (Domande Frequenti)

1. Qual è la differenza tra un array statico e un Vector?
Un array statico ha una dimensione fissa, mentre un Vector può crescere o ridursi dinamicamente durante l’esecuzione del programma.

2. Quando dovrei usare una pila invece di una coda?
Una pila è utile quando devi gestire dati in ordine LIFO (ultimo arrivato, primo servito), come nelle operazioni di undo/redo. Una coda è invece adatta per gestire dati in ordine FIFO (primo arrivato, primo servito), come nella gestione di processi.

3. Come posso gestire la memoria in Java?
Java gestisce automaticamente la memoria attraverso il Garbage Collector, che libera la memoria occupata da oggetti non più referenziati.


Conclusione

Le strutture di dati dinamiche come VectorStack e Queue sono strumenti potenti per gestire collezioni di dati di dimensione variabile. La loro flessibilità le rende ideali per molte applicazioni pratiche, dalla gestione di geometrie complesse alla organizzazione di dati come contatti o appuntamenti.

Sperimenta con gli esempi forniti e prova a implementare le tue strutture di dati dinamiche in Java. Con un po’ di pratica, sarai in grado di utilizzare queste strutture per rendere i tuoi programmi più efficienti e flessibili.


Risorse Aggiuntive

Buon coding! 🚀

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Translate »
Torna in alto