Elenchi collegati in Python

Elenchi collegati in Python

Nodo di origine: 3093495

Introduzione

Una lista collegata è una struttura dati costituita da una sequenza di nodi, ciascuno contenente un valore e un riferimento al nodo successivo nella sequenza. A differenza degli array, gli elenchi collegati non richiedono un'allocazione di memoria contigua, rendendoli più flessibili ed efficienti per determinate operazioni. In questo articolo esploreremo i vantaggi e gli svantaggi delle liste collegate e come implementarle in Python.

Elenchi collegati

Sommario

Vantaggi e svantaggi delle liste collegate

Gli elenchi collegati offrono numerosi vantaggi rispetto ad altre strutture dati. In primo luogo, consentono un efficiente inserimento e cancellazione di elementi, poiché richiedono solo l'aggiornamento dei riferimenti dei nodi vicini. Ciò rende LinkedLists ideale per scenari in cui sono previste modifiche frequenti. Inoltre, le LinkedList possono aumentare o diminuire dinamicamente le loro dimensioni, a differenza degli array, che hanno una dimensione fissa.

Tuttavia, le liste collegate presentano anche alcuni svantaggi. A differenza degli array, gli elenchi collegati non supportano l'accesso casuale agli elementi, il che significa che l'accesso a un elemento in un indice specifico richiede l'attraversamento dell'elenco dall'inizio. Ciò può comportare un rallentamento delle prestazioni per determinate operazioni. Inoltre, le liste collegate richiedono memoria aggiuntiva per memorizzare i riferimenti ai nodi successivi, il che può essere inefficiente per set di dati di piccole dimensioni.

Implementazione di elenchi collegati in Python

Python fornisce un modo flessibile e intuitivo per implementare elenchi collegati. Esistono tre tipi principali di elenchi collegati: elenco collegato singolarmente, elenco collegato doppiamente e elenco collegato circolare. Esploriamo ciascuno di essi in dettaglio.

tipo di elenchi collegati

Elenco collegato singolarmente

Un elenco collegato singolarmente è costituito da nodi in cui ciascun nodo contiene un valore e un riferimento al nodo successivo nella sequenza. Ecco come puoi creare un elenco collegato singolarmente in Python:

class Node:
    def __init__(self, value):
        self.value = value
        self.next = None

class Linked List:
    def __init__(self):
        self.head = None

Creazione di un elenco collegato singolarmente

Per creare un elenco collegato singolarmente, dobbiamo definire una classe Node che rappresenti ciascun nodo nell'elenco. Ogni nodo contiene un valore e un riferimento al nodo successivo. La classe Linked List funge da contenitore per i nodi, con l'attributo head che punta al primo nodo dell'elenco.

Inserimento di nodi in una lista collegata singolarmente

L'inserimento di nodi in una lista collegata singolarmente comporta l'aggiornamento dei riferimenti dei nodi vicini. Ecco un esempio di inserimento di un nodo all'inizio dell'elenco:

def insert_at_beginning(self, value):
    new_node = Node(value)
    new_node.next = self.head
    self.head = new_node

Eliminazione di nodi da un elenco collegato singolarmente

L'eliminazione di nodi da un elenco collegato singolarmente richiede l'aggiornamento dei riferimenti dei nodi vicini. Ecco un esempio di eliminazione di un nodo con un valore specifico:

def delete_node(self, value):
    current = self.head
    if current.value == value:
        self.head = current.next
    else:
        while current.next:
            if current.next.value == value:
                current.next = current.next.next
                break
            current = current.next

Ricerca in un elenco collegato singolarmente

La ricerca di un valore specifico in un elenco collegato singolarmente implica l'attraversamento dell'elenco finché non viene trovato il valore o viene raggiunta la fine dell'elenco. Ecco un esempio di ricerca di un valore:

def search(self, value):
    current = self.head
    while current:
        if current.value == value:
            return True
        current = current.next
    return False

Inversione di un elenco collegato singolarmente

L'inversione di un elenco collegato singolarmente richiede l'aggiornamento dei riferimenti di ciascun nodo in modo che punti al nodo precedente. Ecco un esempio di inversione di un elenco collegato singolarmente:

def reverse(self):
    previous = None
    current = self.head
    while current:
        next_node = current.next
        current.next = previous
        previous = current
        current = next_node
    self.head = previous

Elenco doppiamente collegato

Una lista con collegamento doppio è simile a una lista con collegamento singolo, ma ogni nodo contiene un riferimento sia al nodo successivo che al nodo precedente nella sequenza. Ciò consente una traslazione efficiente in entrambe le direzioni. Ecco come puoi creare una lista doppiamente collegata in Python:

class Node:
    def __init__(self, value):
        self.value = value
        self.next = None
        self.previous = None

class DoublyLinked List:
    def __init__(self):
        self.head = None

Creazione di una lista doppiamente collegata

Per creare una lista doppiamente collegata, definiamo una classe Node che contiene un valore, un riferimento al nodo successivo e un riferimento al nodo precedente. La classe DoublyLinked List funge da contenitore per i nodi, con l'attributo head che punta al primo nodo dell'elenco.

Inserimento di nodi in una lista doppiamente collegata

L'inserimento di nodi in una lista doppiamente collegata comporta l'aggiornamento dei riferimenti dei nodi vicini. Ecco un esempio di inserimento di un nodo all'inizio dell'elenco:

def insert_at_beginning(self, value):
    new_node = Node(value)
    if self.head:
        self.head.previous = new_node
    new_node.next = self.head
    self.head = new_node

Eliminazione di nodi da un elenco doppiamente collegato

L'eliminazione di nodi da un elenco doppiamente collegato richiede l'aggiornamento dei riferimenti dei nodi vicini. Ecco un esempio di eliminazione di un nodo con un valore specifico:

def delete_node(self, value):
    current = self.head
    if current.value == value:
        self.head = current.next
        if self.head:
            self.head.previous = None
    else:
        while current.next:
            if current.next.value == value:
                current.next = current.next.next
                if current.next:
                    current.next.previous = current
                break
            current = current.next

Ricerca in una lista doppiamente collegata

La ricerca di un valore specifico in un elenco doppiamente collegato implica l'attraversamento dell'elenco in entrambe le direzioni finché non viene trovato il valore o viene raggiunta la fine dell'elenco. Ecco un esempio di ricerca di un valore:

def search(self, value):
    current = self.head
    while current:
        if current.value == value:
            return True
        current = current.next
    return False

Inversione di una lista doppiamente collegata

L'inversione di un elenco doppiamente collegato richiede l'aggiornamento dei riferimenti di ciascun nodo per scambiare i puntatori successivo e precedente. Ecco un esempio di inversione di una lista doppiamente collegata:

def reverse(self):
    current = self.head
    while current:
        next_node = current.next
        current.next = current.previous
        current.previous = next_node
        if not next_node:
            self.head = current
        current = next_node

Elenco collegato circolare

Una lista concatenata circolare è una variante di una lista concatenata singola in cui l'ultimo nodo punta al primo nodo, creando una struttura circolare. Ciò consente un attraversamento efficiente da qualsiasi nodo nell'elenco. Ecco come puoi creare una lista collegata circolare in Python:

class Node:
    def __init__(self, value):
        self.value = value
        self.next = None

class CircularLinked List:
    def __init__(self):
        self.head = None

Creazione di una lista collegata circolare

Per creare una lista collegata circolare, definiamo una classe Nodo che contiene un valore e un riferimento al nodo successivo. La classe CircularLinked List funge da contenitore per i nodi, con l'attributo head che punta al primo nodo dell'elenco. Inoltre, il riferimento successivo dell'ultimo nodo viene impostato sulla testa, creando una struttura circolare.

Inserimento di nodi in una lista concatenata circolare

L'inserimento di nodi in una Lista Circolare comporta l'aggiornamento dei riferimenti dei nodi vicini. Ecco un esempio di inserimento di un nodo all'inizio dell'elenco:

def insert_at_beginning(self, value):
    new_node = Node(value)
    if not self.head:
        self.head = new_node
        new_node.next = self.head
    else:
        current = self.head
        while current.next != self.head:
            current = current.next
        current.next = new_node
        new_node.next = self.head
        self.head = new_node

Eliminazione di nodi da una lista collegata circolare

L'eliminazione di nodi da una Lista collegata circolare richiede l'aggiornamento dei riferimenti dei nodi vicini. Ecco un esempio di eliminazione di un nodo con un valore specifico:

def delete_node(self, value):
    if not self.head:
        return
    current = self.head
    if current.value == value:
        while current.next != self.head:
            current = current.next
        if current == self.head:
            self.head = None
        else:
            current.next = self.head.next
            self.head = self.head.next
    else:
        previous = None
        while current.next != self.head:
            previous = current
            current = current.next
            if current.value == value:
                previous.next = current.next
                break

Ricerca in una lista collegata circolare

La ricerca di un valore specifico in un elenco collegato circolare comporta l'attraversamento dell'elenco finché non viene trovato il valore o viene attraversato l'intero elenco. Ecco un esempio di ricerca di un valore:

def search(self, value):
    if not self.head:
        return False
    current = self.head
    while True:
        if current.value == value:
            return True
        current = current.next
        if current == self.head:
            break
    return False

Inversione di una lista collegata circolare

L'inversione di una lista collegata circolare richiede l'aggiornamento dei riferimenti di ciascun nodo per invertire la struttura circolare. Ecco un esempio di inversione di una lista collegata circolare:

def reverse(self):
    if not self.head:
        return
    previous = None
    current = self.head
    next_node = current.next
    while True:
        current.next = previous
        previous = current
        current = next_node
        next_node = next_node.next
        if current == self.head:
            break
    self.head = previous

Operazioni comuni sugli elenchi collegati

Gli elenchi collegati supportano varie operazioni comuni che possono essere eseguite sugli elementi. Esploriamo alcune di queste operazioni:

Accesso agli elementi in un elenco collegato

Per accedere agli elementi di una Lista Collegata possiamo attraversare la lista partendo dal nodo testa e spostarci al nodo successivo fino a raggiungere la posizione desiderata. Ecco un esempio di accesso a un elemento in un indice specifico:

def get_element(self, index):
    current = self.head
    count = 0
    while current:
        if count == index:
            return current.value
        count += 1
        current = current.next
    raise IndexError("Index out of range")

Modifica di elementi in un elenco collegato

La modifica degli elementi in un elenco collegato implica l'attraversamento dell'elenco per trovare l'elemento desiderato e l'aggiornamento del suo valore. Ecco un esempio di modifica di un elemento in un indice specifico:

def modify_element(self, index, new_value):
    current = self.head
    count = 0
    while current:
        if count == index:
            current.value = new_value
            return
        count += 1
        current = current.next
    raise IndexError("Index out of range")

Trovare la lunghezza di una lista collegata

Per trovare la lunghezza di una Lista Collegata, possiamo attraversare la lista e contare il numero di nodi. Ecco un esempio per trovare la lunghezza di una lista collegata:

def get_length(self):
    current = self.head
    count = 0
    while current:
        count += 1
        current = current.next
    return count

Verifica se un elenco collegato è vuoto

Per verificare se una lista collegata è vuota, possiamo semplicemente controllare se il nodo head è None. Ecco un esempio di controllo se un elenco collegato è vuoto:

def is_empty(self):
    return self.head is None

Concatenazione di elenchi collegati

Per concatenare due liste collegate, possiamo attraversare la prima lista per trovare l'ultimo nodo e aggiornare il suo riferimento successivo all'inizio della seconda lista. Ecco un esempio di concatenazione di due elenchi collegati:

def concatenate(self, other_list):
    if not self.head:
        self.head = other_list.head
    else:
        current = self.head
        while current.next:
            current = current.next
        current.next = other_list.head

Elenco collegato e array

Gli elenchi collegati e gli array sono entrambi strutture dati comunemente utilizzate, ma hanno caratteristiche diverse che li rendono adatti a diversi scenari. Confrontiamo elenchi collegati e array in termini di efficienza della memoria, efficienza di inserimento ed eliminazione ed efficienza di accesso casuale.

Efficienza della memoria

Gli elenchi collegati sono più efficienti in termini di memoria rispetto agli array perché non richiedono un'allocazione di memoria contigua. Ogni nodo in una lista collegata deve solo memorizzare il valore e un riferimento al nodo successivo, mentre gli array devono allocare memoria per tutti gli elementi, anche se non vengono utilizzati.

Efficienza di inserimento ed eliminazione

Gli elenchi collegati eccellono nelle operazioni di inserimento ed eliminazione, soprattutto quando gli elementi vengono frequentemente aggiunti o rimossi dal centro dell'elenco. L'inserimento o l'eliminazione di un elemento in un elenco collegato richiede solo l'aggiornamento dei riferimenti dei nodi vicini, mentre gli array potrebbero richiedere lo spostamento degli elementi per accogliere la modifica.

Efficienza dell'accesso casuale

Gli array forniscono un accesso casuale efficiente agli elementi in base ai loro indici, poiché consentono l'indirizzamento diretto della memoria. Al contrario, gli elenchi collegati richiedono l'attraversamento dell'elenco dall'inizio per accedere a un elemento in un indice specifico, con conseguente rallentamento delle prestazioni per le operazioni di accesso casuale.

Scegliere la giusta struttura dei dati

La scelta tra liste collegate e array dipende dai requisiti specifici dell'applicazione. Se sono previste modifiche frequenti e ridimensionamento dinamico, gli elenchi collegati sono la scelta migliore. D'altra parte, se l'accesso casuale e l'efficienza della memoria sono cruciali, gli array sono più adatti.

Applicazioni con elenchi collegati

Ora che abbiamo una buona conoscenza degli elenchi collegati e del loro funzionamento, esploriamo alcune delle applicazioni pratiche in cui gli elenchi collegati possono essere utilizzati in modo efficace.

Lista collegata

Puoi anche iscriverti al nostro Corsi gratuiti Oggi!

Implementazione di pile e code

Una delle applicazioni più comuni degli elenchi collegati è l'implementazione di stack e code. Sia gli stack che le code sono tipi di dati astratti che possono essere facilmente implementati utilizzando elenchi collegati.

Uno stack è una struttura dati che segue il principio LIFO (Last-In-First-Out). Gli elementi vengono aggiunti e rimossi dalla stessa estremità, nota come parte superiore della pila. Gli elenchi collegati forniscono un modo efficiente per implementare gli stack poiché possiamo facilmente aggiungere o rimuovere elementi dall'inizio dell'elenco.

Ecco un esempio di implementazione di uno stack utilizzando un elenco collegato in Python:

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

class Stack:
    def __init__(self):
        self.head = None

    def push(self, data):
        new_node = Node(data)
        new_node.next = self.head
        self.head = new_node

    def pop(self):
        if self.head is None:
            return None
        popped = self.head.data
        self.head = self.head.next
        return popped

Una coda, invece, segue il principio FIFO (First-In-First-Out). Gli elementi vengono aggiunti a un'estremità, detta posteriore, e rimossi dall'altra estremità, detta anteriore. Gli elenchi collegati possono essere utilizzati anche per implementare le code in modo efficiente.

Ecco un esempio di implementazione di una coda utilizzando un elenco collegato in Python:

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

class Queue:
    def __init__(self):
        self.front = None
        self.rear = None

    def enqueue(self, data):
        new_node = Node(data)
        if self.rear is None:
            self.front = new_node
            self.rear = new_node
        else:
            self.rear.next = new_node
            self.rear = new_node

    def dequeue(self):
        if self.front is None:
            return None
        dequeued = self.front.data
        self.front = self.front.next
        if self.front is None:
            self.rear = None
        return dequeued

Gestione di set di dati di grandi dimensioni

Gli elenchi collegati sono utili anche quando si ha a che fare con set di dati di grandi dimensioni. A differenza degli array, gli elenchi collegati non richiedono un'allocazione di memoria contigua. Ciò significa che gli elenchi collegati possono gestire in modo efficiente set di dati di dimensioni variabili senza la necessità di ridimensionarli o riallocarli.

Ad esempio, supponiamo di avere un set di dati di milioni di record e di dover eseguire operazioni come l'inserimento, l'eliminazione o l'attraversamento. L'utilizzo di un array per questa attività può essere inefficiente poiché richiede lo spostamento degli elementi durante l'inserimento o l'eliminazione. Tuttavia, con una lista concatenata, possiamo facilmente inserire o eliminare elementi aggiornando i puntatori, con conseguente operazioni più veloci.

Algoritmi di attraversamento del grafico

Gli algoritmi di attraversamento del grafico, come la ricerca in ampiezza (BFS) e la ricerca in profondità (DFS), possono essere implementati anche utilizzando elenchi collegati. Nell'attraversamento del grafico visitiamo ciascun vertice o nodo di un grafico in un ordine specifico.

Le liste concatenate possono essere utilizzate per rappresentare la lista di adiacenza di un grafico, dove ogni nodo nella lista concatenata rappresenta un vertice e i suoi vertici adiacenti sono memorizzati come nodi della lista concatenata. Questa rappresentazione consente un efficiente attraversamento ed esplorazione del grafico.

Rappresentazione polinomiale

Le liste concatenate possono essere utilizzate per rappresentare i polinomi in modo efficiente. In matematica, i polinomi sono espressioni costituite da variabili e coefficienti. Ogni termine in un polinomio può essere rappresentato come un nodo in una lista concatenata, dove il coefficiente e l'esponente sono memorizzati come dati.

Utilizzando le liste concatenate, possiamo eseguire facilmente operazioni sui polinomi, come addizione, sottrazione e moltiplicazione. I nodi possono essere manipolati per eseguire queste operazioni, ottenendo una rappresentazione concisa ed efficiente dei polinomi.

Playlist musicali e video

Gli elenchi collegati vengono comunemente utilizzati per implementare playlist in lettori musicali e video. Ogni brano o video può essere rappresentato come un nodo in un elenco collegato, in cui i dati contengono informazioni sul file multimediale e il puntatore punta al brano o al video successivo nella playlist.

L'utilizzo di elenchi collegati per le playlist consente una facile navigazione tra brani o video. Possiamo facilmente aggiungere o rimuovere brani dalla playlist aggiornando i puntatori, fornendo un'esperienza utente senza interruzioni.

Conclusione

In conclusione, le liste concatenate sono strutture dati versatili che trovano applicazioni in vari domini. Possono essere utilizzati per implementare stack e code, gestire set di dati di grandi dimensioni, eseguire l'attraversamento di grafici, rappresentare polinomi e creare playlist. Gli elenchi collegati forniscono soluzioni efficienti a questi problemi sfruttando l'allocazione dinamica della memoria e la facile manipolazione dei nodi.

Comprendendo le applicazioni degli elenchi collegati, possiamo prendere decisioni informate nella scelta delle strutture dati per i nostri programmi. Che si tratti di gestire dati, implementare algoritmi o creare interfacce user-friendly, gli elenchi collegati offrono uno strumento prezioso nel toolkit del programmatore.

Pertanto, la prossima volta che riscontri un problema che richiede un inserimento, un'eliminazione o un attraversamento efficienti, considera l'utilizzo di elenchi collegati per semplificare la soluzione e ottimizzare il codice.

Puoi anche leggere altri articoli relativi alle liste Python qui:

Domande frequenti

Q1: Cos'è un elenco collegato?

R: Una lista collegata è una struttura dati composta da nodi, in cui ciascun nodo contiene un valore e un riferimento (o collegamento) al nodo successivo nella sequenza.

Q2: Quali sono i vantaggi dell'utilizzo degli elenchi collegati?

R: Gli elenchi collegati offrono operazioni efficienti di inserimento ed eliminazione, ridimensionamento dinamico e non richiedono un'allocazione di memoria contigua.

Q3: Quali sono gli svantaggi delle liste collegate?

R: Le liste collegate non hanno accesso casuale e richiedono l'attraversamento per l'accesso agli elementi. Inoltre consumano memoria aggiuntiva per l'archiviazione dei riferimenti, il che potrebbe essere inefficiente per set di dati di piccole dimensioni.

Q4: Quali sono i principali tipi di elenchi collegati in Python?

R: I tipi principali di liste collegate sono liste collegate singolarmente, liste collegate doppiamente e liste collegate circolari.

Q5: In quali scenari gli elenchi collegati sono più efficienti in termini di memoria rispetto agli array?

R: Gli elenchi collegati sono più efficienti in termini di memoria rispetto agli array quando si tratta di ridimensionamento dinamico e inserimenti o eliminazioni frequenti, poiché non richiedono un'allocazione di memoria contigua.

Timestamp:

Di più da Analisi Vidhya