Почему ArrayList занимает больше времени для вставки элемента в начале, чем LinkedList в java

#java #list #data-structures #arraylist

#java #Список #структуры данных #arraylist

Вопрос:

я думаю, что ArrayList имеет сложность O (n) для вставки элементов в начале, потому что он сдвигает остальные элементы на одно место вправо. и LinkedList имеет O (n) для вставки элементов в конце, потому что он должен проходить через каждый элемент. таким образом, время, затраченное на обе вышеуказанные операции, должно быть сравнительным, но когда я сделал это практически, потребовалось 34057 миллисекунд для вставки arraylist в начале и только 41 миллисекунду для вставки LinkedList в конце, в то время как оба имеют O (n) временную сложность. почему это так?

с точки зрения сложности пространства, какой из них лучше?

вот мой код

 public void timeTakenEnd(String name, List<Integer> list) {


    for (int i = 0; i < 1E5; i  ) {
        list.add(i);

    }


    long start = System.currentTimeMillis();
    for (int i = 0; i < 1E5; i  ) {
        list.add(i);

    }

    long end = System.currentTimeMillis();

    System.out.println("time taken for: "   name   " to insert elements in the end is  "   (end - start));

}

public void timeTakenBeg(String name, List<Integer> list) {


    for (int i = 0; i < 1E5; i  ) {
        list.add(i);

    }


    long start = System.currentTimeMillis();
    for (int i = 0; i < 1E5; i  ) {
        list.add(0, i);

    }

    long end = System.currentTimeMillis();

    System.out.println("time taken for: "   name   "to insert elements in the beginning is  "   (end - start));

}

public static void main(String[] args) {

    ArrayList<Integer> alist = new ArrayList<Integer>();
    LinkedList<Integer> llist = new LinkedList<Integer>();

    TimeComplexity demo = new TimeComplexity();

    demo.timeTakenEnd("arrarylist", alist); //25 miliseconds on my machine
    demo.timeTakenEnd("linkedlist", llist);//41 miliseconds on my machine

    demo.timeTakenBeg("arraylist", alist);// 34057 miliseconds on my machine
    demo.timeTakenBeg("linkedlist", llist); //60 miliseconds on my machine

}
  

}

Ответ №1:

LinkedList является двусвязным списком. Он запоминает свои первый и последний элементы и позволяет перемещаться по списку в обоих направлениях.

Таким образом, добавление элемента в конец — это просто способ создания узла и назначения указателей a last next и a previous . Это O (1).

Обратите внимание, что Java имеет открытый исходный код, а исходный код поставляется с JDK. Вы могли бы легко найти реализацию:

 public boolean add(E e) {
    linkLast(e);
    return true;
}

void linkLast(E e) {
    final Node<E> l = last;
    final Node<E> newNode = new Node<>(l, e, null);
    last = newNode;
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size  ;
    modCount  ;
}
  

Комментарии:

1. теперь это имеет смысл, я не знал, что он реализован как дважды linkedlist в java, спасибо, приятель

Ответ №2:

Как показывает его имя (и Javadoc), ArrayList он внутренне реализован массивами.

Итак, вставка элемента включает перемещение всех элементов за ним на одну позицию вперед.

С другой стороны, a LinkedList нужно только перенаправить ссылки на элементы, чтобы вставить новый узел, поэтому его время более постоянное.

Ответ №3:

Список массивов использует непрерывное хранилище, поэтому для вставки в начале требуется либо переместить все существующие элементы на единицу вверх, либо перераспределить весь список. Связанный список может поместить новый элемент в любом месте, если ссылки настроены правильно. Нет необходимости перемещать другие элементы списка, просто настройте несколько ссылок.