Skip to the content
Software Made Clear Diagrams that show the mechanism About

Linked lists

ANSWER

Inserting in the middle costs nothing only if you already hold the node. Finding that node costs a full walk, and that walk is what decides almost every real comparison against an array.

IN PLAIN TERMS

Each item only points at the next one, like clues in a treasure hunt. Slipping an extra clue into the middle is easy, because you rewrite just two of them. But there is no way to jump straight to the ninth clue — you have to follow the first eight to get there.

The linked list is usually taught as the structure that beats an array at insertion, and that claim is true in a narrow way which almost never matches what people actually do with it. The insertion really is a couple of pointer writes, however long the list is. What it takes to be standing in the right place to make them is the part the claim leaves out, and once you count that, most of the cases people reach for a linked list are cases an array handles better.

The pointer is the whole idea#

A linked list stores each value in its own small object — a node — and each node holds the address of the next one. Nothing else connects them. There is no block of memory holding the sequence, no arithmetic that turns position seven into an address, and no requirement that any two nodes sit anywhere near each other. The order lives entirely in the pointers.

That one design choice decides everything else, in both directions. Adding a value between two existing ones means making a node and rewriting two pointers, and no other node has to move or even notice. Compare that with an array, where inserting at the front means shifting every element up a place to make room — the cost a Python list pays on every pop from the left. But the same choice means position seven is not a computation. It is a walk: start at the head and follow seven pointers, because the only thing that knows where the eighth node lives is the seventh.

So the honest summary is not “insertion is fast, indexing is slow”. It is that a linked list has no notion of position at all — only of next. Every operation that sounds positional is really a walk with something done at the end of it, and the walk is the part that costs.

Why the array usually wins anyway#

Take the comparison people usually have in mind: iterate a large collection and remove some of the items as you go. Both structures visit n elements, so on step count they are level, and the linked list looks better because its removals are pointer writes rather than shifts of everything to the right.

On a real machine the array usually wins anyway, and the reason is where the elements sit. An array is one contiguous block, so the processor fetches a chunk at a time and the next several elements are already in hand when the loop asks for them. A linked list’s nodes were allocated separately and can sit anywhere, so following a pointer can mean waiting on a fresh fetch from memory — once per element, with nothing useful to overlap the wait. Step counting cannot see any of this, because it was never measuring memory. It is the same gap that decides how a storage engine chooses to lay its data out on disk, one level further down.

This is why standard libraries do not hand you a linked list by default. Java has one, and its documentation quietly says what it is for by naming what it implements: LinkedList is a doubly-linked implementation of both List and Deque. The second of those is the honest use — work at the ends, not in the middle.

Indexing a list inside a loop#

The failure that costs real time is indexing a linked list inside a loop. Written out, it looks like ordinary code: a counter from zero to the size, and a get at each step. On an array that is one pass. On a linked list every get starts another walk, so the loop does roughly half of n squared pointer hops — and it does them quietly. No error, no warning, just a function that was fine on test data and takes minutes on the real thing.

Java’s LinkedList softens this without removing it. Its documentation states that operations which index into the list traverse from the beginning or the end, whichever is closer to the index requested. That is a real improvement, and the average walk genuinely halves. It is still a walk, and halving a quadratic leaves a quadratic.

The second failure shows up in tests rather than in timings. A node keeps its identity while the list changes around it, which is a genuine strength — and it also means anything holding a node is holding a live reference into a structure somebody else may be editing. Java’s iterators for this class are documented as fail-fast: a structural change made behind an iterator’s back gets you a ConcurrentModificationException rather than silently wrong results. The documentation is careful that this is a way to find bugs and not a guarantee to write programs against — the check is best-effort, so a program that depends on the exception being thrown depends on something the class does not promise.

IF YOU REMEMBER ONE THING

A linked list knows nothing about position, only about next. Every cost on this page follows from that — including the one it is famous for being good at.

Questions people also ask

5 QUESTIONS
Is inserting into a linked list really O(1)?

The insertion is. Getting to the place you want to insert is not, and the two are almost always the same operation in practice. If you already hold a reference to the node — because you kept one, or because you are mid-traversal — then splicing in a new node is a couple of pointer writes and the size of the list does not matter. If all you have is an index or a value, you pay a walk to find it first, and that walk is O(n).

When is a linked list actually the right choice?

When you already hold node references and splice frequently, and when stable identity matters — a node keeps its address while the list changes around it, which an array cannot promise, because growing one moves every element to a new block. For a collection you mostly index into or iterate straight through, an array-backed structure is the better default.

Why is a linked list slower than an array if both are O(n) to scan?

Because the notation counts steps and the machine pays for where those steps land. An array's elements sit next to each other, so one memory fetch brings in several of them at once. A linked list's nodes can sit anywhere, so each hop can be a fresh fetch that waits on memory. Same step count, very different wall-clock.

What is the difference between a singly and a doubly linked list?

A singly linked node knows only its successor; a doubly linked node knows both neighbours. The second pointer costs memory on every node and buys two things: walking backwards, and removing a node you already hold without first finding the one before it. Java's LinkedList is doubly linked, which is what lets it also serve as a Deque.

Does Java's LinkedList walk from the start every time I index it?

Not quite. Its documentation states that operations which index into the list traverse from the beginning or the end, whichever is closer to the index requested. That halves the average walk and changes nothing about the growth — a call in the middle of a million-element list still touches half a million nodes, and doing that inside a loop is the classic way to turn one pass into a quadratic one.