2016-10-08 5 views
0

Я реализую односвязный список в Java. Что мне не нравится в этом коде, так это то, что я должен проверять if (head.next == null) каждый раз, когда добавляю элемент. Но условие выполняется только один раз, когда добавляется первый элемент.Добавление элемента в отдельный список в Java

Есть ли способ реализовать однонаправленный некруглый список без такого условия?

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

Почему вам нужно 'last' объект? – Maroun

+0

@MarounMaroun, потому что мне нужно добавить элементы в список. На самом деле, метод 'add' следует называть' addLast' –

+0

@MarounMaroun, как вы думаете, 'last' является избыточным? Я видел несколько примеров, когда у них есть только указатель на голову и повторяется над списком, чтобы добавить элемент в конец. Таким образом, добавление будет принимать O (n), тогда как вложение в односвязный список должно принимать O (1). См. Также http://bigocheatsheet.com/ –

ответ

1

Вы можете инициализировать последний будет указывать на голову, а затем ваш, если избыточна:

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

Спасибо! Теперь я понимаю, почему это работает. Поэтому 'last' содержит ссылку на ту же память, что и' head'. Поэтому при добавлении первого элемента 'last.next = newNode;' означает, что 'last.next' **, а также' head.next' ** будет содержать ссылку на первый добавленный элемент. –

1

Есть много случаев, когда «хороший дизайн OO» позволяет обходиться без если/другое проверки; чаще всего, используя некоторую форму полиморфизма.

Значение: вместо запроса какого-либо объекта о некотором свойстве, чтобы затем принять решение по этому поводу в коде клиента, вы как-то убедитесь, что ваш код клиента может просто вызвать метод на каком-либо другом объекте. И тогда «if» «скрыт» внутри кода, который первоначально сгенерировал этот «другой объект» и передал его вашему коду клиента. (вы найдете несколько приятных примеров, как это работает в этих videos).

Но - я думаю, что в этом случае это будет явным излишеством!

Дело в том, что с точки зрения удобочитаемости эта проверка действительно не повредит (возможно, вы могли бы реорганизовать вещи на большее количество методов). И производительность ... тоже не имеет значения. Если ваш код вызывается так часто, что это имеет значение, JIT в любом случае ударит, и, вероятно, создаст код, который в большинстве случаев берет правильную ветку.

Таким образом: это хорошая реализация; и я думаю, вы не должны беспокоиться об этом, если-проверьте там!

Смежные вопросы