Common data structure operations

Data structureTime complexitySpace complexity
Average (or amortized, see notes)WorstWorst
AccessSearchInsertionDeletionAccessSearchInsertionDeletion
ArrayΘ(1)Θ(n)Θ(n)Θ(n)O(1)O(n)O(n)O(n)O(n)
StackaΘ(n)Θ(n)Θ(1)Θ(1)O(n)O(n)O(1)O(1)O(n)
QueueaΘ(n)Θ(n)Θ(1)Θ(1)O(n)O(n)O(1)O(1)O(n)
Singly-linked listbΘ(n)Θ(n)Θ(1)Θ(1)O(n)O(n)O(1)O(1)O(n)
Doubly-linked listbΘ(n)Θ(n)Θ(1)Θ(1)O(n)O(n)O(1)O(1)O(n)
Skip listcΘ(log n)Θ(log n)Θ(log n)Θ(log n)O(n)O(n)O(n)O(n)O(n log n)
Hash tabledN/AΘ(1)Θ(1)Θ(1)N/AO(n)O(n)O(n)O(n)
Binary search treeeN/AO(h)O(h)O(h)N/AO(n)O(n)O(n)O(n)
Cartesian treefN/AΘ(log n)Θ(log n)Θ(log n)N/AO(n)O(n)O(n)O(n)
B-treeΘ(log n)Θ(log n)Θ(log n)Θ(log n)O(log n)O(log n)O(log n)O(log n)O(n)
Red-black treeΘ(log n)Θ(log n)Θ(log n)Θ(log n)O(log n)O(log n)O(log n)O(log n)O(n)
Splay treegN/AΘ(log n)Θ(log n)Θ(log n)N/AO(n)O(n)O(n)O(n)
AVL treeΘ(log n)Θ(log n)Θ(log n)Θ(log n)O(log n)O(log n)O(log n)O(log n)O(n)
KD treehΘ(log n)Θ(log n)Θ(log n)Θ(log n)O(n)O(n)O(n)O(n)O(n)

Average, amortized, and worst case

These three words describe different things, so the tables do not treat them as interchangeable.

Worst case
The most work a single operation can need, on the least favorable input. It holds no matter what the data looks like.
Average (expected) case
The cost averaged over a stated assumption, such as random keys, random insertion order, or a hash function that spreads keys evenly. If the assumption fails, the bound can fail with it.
Amortized case
The cost per operation when you average over a whole sequence of operations, with no randomness involved. An occasional expensive operation (like a resize) is paid for by many cheap ones, but a single operation can still be slow.

Where a bound is tight, it is written with Θ; worst-case columns use O as an upper bound. Implementation details and assumptions behind specific rows are in the notes below.

  1. Stack and queue. Push, pop, enqueue, and dequeue are O(1) when built on a linked list, a circular buffer, or a dynamic array used at one end (a dynamic array's push is amortized O(1)). A queue on a plain array that shifts every element after removing from the front, such as Python's list.pop(0), takes O(n) per dequeue.
  2. Linked lists. Insertion and deletion are O(1) only when you already hold a reference to the position: the head, or the node before it in a singly-linked list. Finding that position takes O(n).
  3. Skip list. Search, insertion, and deletion are expected bounds that come from random level choices; the worst case is O(n). Space is O(n) in expectation; O(n log n) is the worst case when levels are capped at log n.
  4. Hash table. Θ(1) is the expected cost assuming a good hash function that spreads keys evenly and a load factor kept bounded by resizing. If many keys collide, a single operation can take O(n). Insertion is also amortized, because a resize rehashes every key.
  5. Binary search tree. An ordinary BST costs O(h) for search, insertion, and deletion, where h is its height. That is Θ(log n) when the tree is balanced or keys arrive in random order, and O(n) in the worst case, such as inserting sorted keys. Self-balancing trees (AVL, red-black, B-tree) keep h at O(log n) and so give a worst-case guarantee. A BST does not support access by position.
  6. Cartesian tree. The Θ(log n) figures assume random priorities, as in a treap. A tree built from adversarial or already-ordered input can degrade to O(n).
  7. Splay tree. Θ(log n) is an amortized bound over a sequence of operations. A single operation can take O(n), even though the average over many operations is O(log n).
  8. KD tree. The Θ(log n) figures assume points that keep the tree reasonably balanced. Nearest-neighbor search in high dimensions can degrade toward O(n).

More data structures

These structures answer different questions than the table above, so each lists the operations it is actually used for. In the trie rows, m is the key length.

Data structureOperationTimeSpaceNotes
Dynamic arrayAccess by indexO(1)O(n)Python list, Java ArrayList, C++ vector. Capacity grows geometrically, so most appends are cheap and an occasional append copies everything.
AppendO(1) amortized, O(n) worst
Insert or delete in the middleO(n)
Remove lastO(1)
Search (unsorted)O(n)
Binary heapPeek min or maxO(1)O(n)Stored in an array. Heaps give fast access to one extreme, not sorted order or fast search.
InsertO(log n) worst, O(1) average*
Extract min or maxO(log n)
Build from n itemsO(n)
Update or delete at a known positionO(log n)
Search for a valueO(n)
TrieInsertO(m)O(n·m) nodesCost depends on key length, not on how many keys are stored. Child arrays multiply space by the alphabet size; hash-map children save space.
SearchO(m)
DeleteO(m)
Find all keys with a prefixO(m + k) for k results
Disjoint-set union (Union-Find)Make setO(1)O(n)With path compression and union by rank or size, find and union cost amortized O(α(n)), which is at most 4 for any practical n. Without both, a find can take O(n).
FindO(α(n)) amortized
UnionO(α(n)) amortized
Monotonic stackPush or popO(1)O(n)A stack that keeps its items in sorted order by popping anything that breaks the order. Each item is pushed and popped at most once, so problems like next greater element take O(n) in total, not O(n2).
PeekO(1)
Process n items (whole pass)O(n) amortized
DequePush or pop at either endO(1)O(n)C++ deque supports O(1) indexing. Java ArrayDeque supports end operations but has no indexed-access API. Python collections.deque uses linked blocks, so indexing near the middle is O(n). A monotonic deque solves sliding-window maximum in O(n).
Peek either endO(1)
Access by indexO(1) ring buffer, O(n) linked blocks
SearchO(n)

Priority queue implementations

A priority queue is an interface, not a single structure. The cost of each operation depends on what sits underneath.

ImplementationPeekInsertExtract min or maxDecrease keyNotes
Unsorted arrayO(n)O(1)O(n)O(1) at a known indexFine for small n or when extracts are rare.
Sorted arrayO(1)O(n)O(1) from the sorted endO(n)Fine when extracts far outnumber inserts.
Binary heapO(1)O(log n)O(log n)O(log n)The default choice. Python heapq, Java PriorityQueue, and C++ priority_queue use it. Most do not support decrease-key directly.
Fibonacci heapO(1)O(1) amortizedO(log n) amortizedO(1) amortizedBest asymptotics for Dijkstra and Prim, but large constants make binary heaps faster in practice.

Graph representations

A graph has V vertices and E edges. The representation you pick decides which operations are cheap. Here deg(v) is the number of edges at vertex v.

OperationAdjacency listAdjacency matrixEdge list
SpaceO(V + E)O(V2)O(E)
Check whether edge (u, v) existsO(deg(u))*O(1)O(E)
Iterate neighbors of vO(deg(v))O(V)O(E)
Iterate all edgesO(V + E)O(V2)O(E)
Add edgeO(1)O(1)O(1)
Remove edgeO(deg(u))*O(1)O(E)
Add vertexO(1)O(V2)**O(1)
Best forSparse graphs and traversals such as BFS, DFS, and Dijkstra.Dense graphs and algorithms that test many edges, such as Floyd–Warshall.Algorithms that sort or scan every edge, such as Kruskal and Bellman–Ford.

The same graph three ways

An undirected graph with four vertices and edges 0–1, 0–2, 1–3, and 2–3.

Adjacency list

0: [1, 2]
1: [0, 3]
2: [0, 3]
3: [1, 2]

Adjacency matrix

    0 1 2 3
0 [ 0 1 1 0 ]
1 [ 1 0 0 1 ]
2 [ 1 0 0 1 ]
3 [ 0 1 1 0 ]

Edge list

(0, 1)
(0, 2)
(1, 3)
(2, 3)

Topics on this page

Each one has its own page with an explanation, code, and the mistakes people make.

Keyboard shortcuts

/
Search topics
?
Show this list of shortcuts
r
Open the revision sheet
b
Save or unsave the focused card, or the topic you are reading
l
Mark the focused card, or the topic you are reading, as learned
Space Left arrow Right arrow
In the visualizer: play or pause, step back, step forward
1 to 4 Enter
In the quiz: pick an answer, then go to the next question
Escape
Close this list