Se si dispone di un elenco circolare collegato, ciascun nodo punta al nodo successivo in un ciclo continuo. Quindi non c'è l'ultimo e non il primo. In questa situazione, hai solo bisogno di un puntatore nella struttura dati (che la domanda chiama "corrente") perché puoi percorrere l'intero elenco fino a quando non torni al punto in cui hai iniziato.
Un nodo potrebbe essere simile a questo:
public class ListNode<T> {
private T element;
private ListNode<T> next;
}
Quindi, in questo ambiente, quando si aggiunge il primo nodo alla lista, è puntatore "next" punterà a se stesso. Quando aggiungi il secondo nodo, ciascun puntatore "successivo" punta all'altro. Quando si aggiunge il terzo nodo, ognuno punta a quello successivo e presumibilmente questo viene ordinato in qualche modo. Ogni nodo aggiuntivo aggiunto verrà inserito nella posizione appropriata nel ciclo.
Un buon utilizzo per una struttura dati come questa sarebbe un programma che viene ripetuto ogni giorno o ogni ora. Tutti gli eventi possono essere memorizzati in un elenco circolare e il puntatore "corrente" punta sempre a quello che è in programma successivamente.
Ovviamente, quando si cerca una lista come questa, è necessario mantenere un riferimento al primo nodo. Questo è l'unico modo per sapere se hai cercato l'intero elenco poiché non termina con un puntatore "successivo" nullo.
Modifica: Come discusso nei (numerosi) commenti seguenti, un puntatore "a coda" sembra essere una buona idea qui per le operazioni di inserimento. Ecco il metodo originale che ho postato, che è stato rinominato insertAfter
:
public void insertAfter(int data) {
Link newLink = new Link(data);
if (current == null) {
newLink.next = newLink;
current = newLink;
} else {
newLink.next = current.next;
current.next = newLink;
}
}
Un puntatore coda sarebbe sempre puntare al l'ultimo nodo della lista. Questo sarebbe anche il nodo prima del primo nodo, poiché la lista è circolare. Quindi, assicurati di mantenere (tail.next == current)
durante la manipolazione dei puntatori. Ecco il nuovo metodo di inserimento:
public void insert(int data) {
Link newLink = new Link(data);
if (current == null) {
current = newLink;
tail = newLink;
newLink.next = newLink; // tail.next = current!
} else {
tail.next = newLink; // tail.next = current!
newLink.next = current;
current = newLink; // tail is unchanged, newLink is current
}
}
L'inserimento di valori dovrebbe giustamente metterli fuori ordine. Per mantenere l'ordine durante l'aggiunta, un metodo add
dovrebbe essere utilizzato:
public void add(int data) {
this.insert(data);
this.advance();
}
Ecco il codice per advance
:
public void advance() {
if (current != null) {
tail = current;
current = tail.next; // tail.next = current!
}
}
Quando viene utilizzato come questo per creare liste ...
list1.add(1);
list1.add(2);
list1.add(3);
list2.insert(3);
list2.insert(2);
list2.insert(1);
... entrambe le liste sono ordinate 1-2-3 con 1 come corrente.
Quindi, le operazioni come insertAfter e DeleteAt verranno eseguite normalmente assumendo che si abbia un riferimento al primo ("corrente"), che il corrente debba essere il primo nodo o che possa essere ovunque? – sam2015
Sembra che "corrente" possa essere ovunque poiché non esiste un "primo" nodo. Se la definizione dei dati richiede un "primo" nodo definitivo, non sarebbe opportuno utilizzare un elenco circolare. In una lista concatenata, non ha senso usare gli indici per identificare i nodi. Se si chiama 'deleteAt (2)' per esempio - che è 2 da dove? Cos'è zero? –
Per un elenco circolare circolare, tutti i metodi che eseguono operazioni basate su un indice devono utilizzare un indice relativo al nodo "corrente". Questo perché questo è l'unico punto di accesso alla struttura dati. –