2

When adding an element at a certain index using the add(index, element) method in an ArrayList, it places the element at that index, while all the other elements change their indexes by 1 (they move in memory). That's why an ArrayList has the complexity O(n) when adding an element at a certain position.

In case of a doubly LinkedList, I know that the elements have pointers to the previous element and also for the next one.

My question is, when using the add(index, element) method related to a LinkedList, what will actually happen behind the scenes? I know that using the LinkedList the rest of the elements don't move in memory, so how come they can still be placed at a certain index without moving in memory?

1
  • 1
    The indices on a LinkedList don't correspond to contiguous memory locations. Instead, the get() method requires a list traversal to access the correct index. This is why ArrayList::get has a complexity of O(1) (it can just jump to the correct memory address), but LinkedList::get has a complexity of O(n). Commented Sep 23, 2019 at 15:23

2 Answers 2

2

Adding a new element to a linked list at a specified index requires walking down the list (from either the head or tail), and then splicing in the new element. The source code for LinkedList#add(int index, E element) reveals as much:

public void add(int index, E element) {
    checkPositionIndex(index);

    if (index == size)
        linkLast(element);
    else
        linkBefore(element, node(index));
}

Should the index be pointing to the final item in the list, it simply appends a new node to the end. Otherwise, it calls linkBefore(), which does a bit of splicing work (I won't bother to include its source code as well).

Note here that adding a new node to a linked list does not necessarily involve moving anything in the already existing list. Rather, it mostly involves moving around references in the background.

Sign up to request clarification or add additional context in comments.

2 Comments

@Michael I actually was worried someone would call me out on that. I changed my language a bit.
Welcome to pedant country
1

The implementation of add(index, element) looks like this:

public void add(int index, E element) {
    checkPositionIndex(index);

    if (index == size)
        linkLast(element);
    else
        linkBefore(element, node(index));
}

If you're adding an element to the tail of the LinkedList, the linkLast method can be executed in constant time; the LinkedList always has direct access to its last element, and no traversing is required.

Otherwise, the node method is what's expensive, as a traversal through at most half of the list is required:

Node<E> node(int index) {
    // assert isElementIndex(index);

    if (index < (size >> 1)) {
        Node<E> x = first;
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else {
        Node<E> x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}

The elements aren't required to move in memory because they each refer to their previous and next nodes in the LinkedList, as you can see below in linkBefore:

void linkBefore(E e, Node<E> succ) {
    // assert succ != null;
    final Node<E> pred = succ.prev;
    final Node<E> newNode = new Node<>(pred, e, succ);
    succ.prev = newNode;
    if (pred == null)
        first = newNode;
    else
        pred.next = newNode;
    size++;
    modCount++;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.