2016-10-08 7 views
0

Ich implementiere eine einfach verkettete Liste in Java. Was ich an diesem Code nicht mag ist, dass ich jedes Mal, wenn ich ein Element hinzufüge, if (head.next == null) überprüfen muss. Aber die Bedingung wird nur einmal erfüllt, wenn das erste Element hinzugefügt wird.Hinzufügen eines Elements zu einer einfach verknüpften Liste in Java

Gibt es eine Möglichkeit, eine einfach verknüpfte nicht-zirkuläre Liste ohne eine solche Bedingung zu implementieren?

package sample; 

import java.util.Iterator; 
import java.util.NoSuchElementException; 

public class SinglyLinkedList<T> implements Iterable<T> { 

    private Node<T> head = new Node<T>(null); 
    private Node<T> last = null; 

    public SinglyLinkedList(T... elements) { 
     addAll(elements); 
    } 

    public void add(T element) { 
     if (head.next == null) { 
      head.next = new Node<T>(element); 
      last = head.next; 
     } else { 
      Node<T> newNode = new Node<T>(element); 
      last.next = newNode; 
      last = last.next; 
     } 
    } 

    public void addAll(T... elements) { 
     for (T element : elements) { 
      add(element); 
     } 
    } 

    @Override 
    public String toString() { 
     Iterator<T> iterator = iterator(); 
     if (!iterator.hasNext()) { 
      return "[]"; 
     } 
     StringBuilder builder = new StringBuilder(); 
     builder.append("["); 
     while (iterator.hasNext()) { 
      T element = iterator.next(); 
      builder.append(element); 
      if (!iterator.hasNext()) { 
       return builder.append("]").toString(); 
      } 
      builder.append(", "); 
     } 
     return builder.toString(); 
    } 

    @Override 
    public Iterator<T> iterator() { 
     return new Iterator<T>() { 

      Node<T> current = head; 

      @Override 
      public boolean hasNext() { 
       return current.next != null; 
      } 

      @Override 
      public T next() { 
       if (!hasNext()) { 
        throw new NoSuchElementException(); 
       } 
       Node<T> temp = current; 
       current = current.next; 
       return temp.next.element; 
      } 

     }; 
    } 

    private static class Node<T> { 

     private Node<T> next; 
     private T element; 

     Node(T element) { 
      this.element = element; 
     } 

     @Override 
     public String toString() { 
      return element.toString(); 
     } 
    } 
} 
+1

Warum Sie das 'last' Objekt brauchen? – Maroun

+0

@MarounMaroun, weil ich Elemente an die Liste anhängen muss. Eigentlich sollte die Methode 'add'' 'addLast' genannt werden. –

+0

@MarounMaroun, denkst du' last' ist überflüssig? Ich sah einige Beispiele, wenn sie nur den Kopfzeiger haben und über die Liste iterierten, um ein Element am Ende hinzuzufügen. Somit würde die Addition O (n) annehmen, wohingegen die Insertion in eine einfach verknüpfte Liste O (1) annehmen sollte. Siehe auch http://bigocheatsheet.com/ –

Antwort

1

könnten Sie initialisieren zuletzt den Kopf zu zeigen und dann, wenn redundant ist:

private Node<T> head = new Node<T>(null); 
private Node<T> last = head; 

public void add(T element) { 
     Node<T> newNode = new Node<T>(element); 
     last.next = newNode; 
     last = last.next; 
} 
+0

Danke! Jetzt verstehe ich, warum es funktioniert. So hat 'last' einen Verweis auf den gleichen Speicher wie' head'. Wenn also das erste Element hinzugefügt wird, bedeutet "last.next = newNode;", dass 'last.next' ** sowie' head.next' ** einen Verweis auf das erste hinzugefügte Element enthalten. –

1

Es gibt viele Fälle, in denen „gutes OO-Design“ ermöglicht es Ihnen, ohne zu gehen, wenn/sonst Kontrollen; am häufigsten mit einer Form von Polymorphie.

Bedeutung: anstatt einige Objekte über eine Eigenschaft zu fragen, um dann eine Entscheidung darüber in Ihrem Client-Code zu treffen, stellen Sie irgendwie sicher, dass Ihr Client-Code einfach eine Methode auf einem anderen Objekt aufrufen kann. Und dann ist das "if" innerhalb des Codes verborgen, der dieses "andere Objekt" ursprünglich erzeugt und an Ihren Client-Code weitergegeben hat. (Sie finden einige schöne Beispiele, wie das in diesen videos funktioniert).

Aber - ich denke, das wäre in diesem Fall klar Overkill!

Der Punkt ist: aus Sicht der Lesbarkeit, dass eine Überprüfung wirklich nicht weh tut (Sie könnten Dinge in mehr Methoden vielleicht umgestalten). Und Leistung ... ist auch egal. Wenn Ihr Code so oft aufgerufen wird, dass es wichtig ist, wird der JIT trotzdem eingreifen und wahrscheinlich Code erstellen, der in den meisten Fällen den richtigen Zweig direkt übernimmt.

Also: das ist eine nette Implementierung; und ich denke, du solltest dir darüber keine Sorgen machen, wenn du da nachschaust!

Verwandte Themen