Skip to content
dsa/roadmap
← All cheat sheets
02

Linear Structures

dsa.fetehadin.com
2.1 Arrays & 2-D Arrays (Review)

Arrays store items side by side in memory, which is why reading any index is instant. 2-D arrays are stored row by row.

Access a[i]O(1)
Search (unsorted)O(n)
Insert / delete at position iO(n): shift items
Insert / delete at the endO(1) if there is space
Traverse an R Γ— C matrixO(RΒ·C)
SpaceO(n) for n items
  • βœ—Using 1-based indexes. C++ arrays start at 0, so the last valid index is n βˆ’ 1.
  • βœ—Writing a[n] (out of bounds). C++ does not check, so it silently corrupts memory.
  • βœ—Using sizeof(a)/sizeof(a[0]) inside a function. There, a is a pointer, so the trick gives the wrong size. Pass n instead.
2.2 Singly Linked List

Nodes on the heap, each pointing to the next. Insert at front, end or a position, delete by value, search and traverse, plus the dummy-node trick and the classic pitfalls.

Insert at frontO(1)
Insert at endO(n), or O(1) with a tail pointer
Insert at position kO(k)
Delete by value / searchO(n)
Access the i-th itemO(n): no random access
SpaceO(n) plus one pointer per node
  • βœ—Losing the list by updating head before linking the new node (head = n; first).
  • βœ—Dereferencing temp->next without checking temp != nullptr.
  • βœ—Forgetting the empty-list and delete-the-head special cases.
2.3 Doubly Linked List

Each node points both forward and backward. You can walk in both directions and delete a node knowing only its address, at the cost of one extra pointer per node.

Insert / delete at front or end (with tail)O(1)
Delete a node you already have a pointer toO(1): no need to find prev
Search / delete by valueO(n)
Traverse backwardO(n): impossible in a singly list without extra memory
SpaceO(n), with 2 pointers per node
  • βœ—Updating next but forgetting prev (or the reverse). Each insert or delete touches both directions.
  • βœ—Forgetting cur->next->prev when cur->next is nullptr (deleting the tail) β†’ crash.
  • βœ—Not updating tail when deleting the last node.
2.4 Stacks with an Array

Last in, first out. The stack ADT (push, pop, peek, isEmpty, isFull) built on a fixed array with a top index, plus overflow and underflow.

pushO(1)
popO(1)
peek / isEmpty / isFullO(1)
search for a valueO(n): not a stack operation
SpaceO(MAX), fixed when the array is declared
  • βœ—Writing st[top++] = x with top = -1 (writes to index βˆ’1). Use st[++top] = x.
  • βœ—Popping without checking isEmpty() (underflow).
  • βœ—Pushing without checking isFull() (writes past the array).
2.5 Stacks with a Linked List

The same stack ADT, but the top is the head of a linked list. No fixed capacity, push and pop stay O(1), and the bracket-matching application.

push (insert at head)O(1)
pop (delete head)O(1)
peek / isEmptyO(1)
SpaceO(n), one node (data + pointer) per item
  • βœ—Using the tail as the top, making pop O(n).
  • βœ—Forgetting delete in pop (memory leak).
  • βœ—Reading top->data after deleting the node. Save the value first.
2.6 Queues with an Array

First in, first out. Why a naive array queue makes dequeue O(n), how a front index makes it O(1), and the wasted-slot problem that leads to the circular queue.

enqueue (at rear)O(1)
dequeue, naive (shift left)O(n)
dequeue, with front indexO(1)
front / isEmptyO(1)
SpaceO(MAX)
  • βœ—Confusing front and rear (items enter at the rear, leave at the front).
  • βœ—Dequeuing without checking for empty.
  • βœ—With a front index, testing rear == -1 for empty. The correct test is front > rear.
2.7 Queues with a Linked List

Keep two pointers, front and rear. Enqueue at the rear and dequeue at the front, both O(1), with no capacity limit.

enqueue (insert after rear)O(1)
dequeue (delete front)O(1)
peek / isEmptyO(1)
SpaceO(n)
  • βœ—Dequeuing from the tail (needs the previous node, so O(n)).
  • βœ—Forgetting rear = nullptr when the queue becomes empty. The next enqueue then writes through a dangling pointer.
  • βœ—Enqueue into an empty queue without setting both front and rear.
2.8 Circular Queue

Let front and rear wrap around with the modulo operator, so freed slots are reused. All operations O(1) on a fixed array.

enqueueO(1)
dequeueO(1)
front / isEmpty / isFullO(1)
SpaceO(N), and every slot is usable
  • βœ—Writing rear++ instead of rear = (rear + 1) % N.
  • βœ—Testing front == rear for both empty and full. Without a count (or one spare slot) they look the same.
  • βœ—Printing from 0 to rear instead of starting at front and wrapping.
2.9 std::stack, std::queue & std::deque

The standard library versions you will use in real code and on LeetCode, their method names, and the classic traps (pop returns void, empty checks).

stack push / pop / topO(1)
queue push / pop / front / backO(1)
deque push/pop at either endO(1)
deque d[i]O(1)
SpaceO(n)
  • βœ—Writing int x = s.pop();. It does not compile; pop() returns void. Read top() first.
  • βœ—Calling top() / front() / pop() on an empty container (undefined behaviour). Check empty().
  • βœ—Using q.top() on a queue (it is front()), or s.front() on a stack (it is top()).
Row-major order:
How C++ stores a 2-D array: row 0 first, then row 1. Address of a[i][j] = base + (iΒ·cols + j)Β·size.
Node:
One element of a linked structure: data plus pointer(s) to other nodes.
Head:
Pointer to the first node of a linked list.
Dummy (sentinel) node:
A fake node placed before the head so every real node has a predecessor.
Doubly linked list:
Each node has both next and prev pointers, allowing backward traversal and O(1) delete given a node.
Stack:
LIFO collection: push and pop at the top only.
LIFO:
Last In, First Out.
Overflow / underflow:
Pushing onto a full stack / popping from an empty one.
Queue:
FIFO collection: enqueue at the rear, dequeue from the front.
FIFO:
First In, First Out.
Circular queue:
Array queue whose indices wrap around with % N so freed slots are reused.
Deque:
Double-ended queue: insert and remove at both ends in O(1).

Keyboard shortcuts

⌘K /
Search topics, glossary, cheat sheets
space
Play / pause the visualizer
← β†’
Step back / forward
r
Reset the visualizer
?
Show this help