Fundamental data structures in C: linked list, stack, and queue.
π What to learn on this page
β Must-know essentials
Linked list: each node points to the next
Stack: last-in first-out (LIFO)
Queue: first-in first-out (FIFO)
β Read if you have time
Trees and hash tables
Complexity: O(n), O(1)
Comparison with STL / standard libraries
What is a Data Structure? β Designing How Data is Arranged
A data structure defines how data is laid out in memory and how it is manipulated. Arrays are themselves a data structure, but there are situations where arrays alone are inconvenient.
Limitations of arrays
Slow middle/front insertion
To insert near the front, all the later elements must be shifted. With a million items, that's a million shifts.
Fixed size
The size is fixed at declaration, which is awkward for data that grows and shrinks (malloc helps, but it's extra work).
Common data structures
Structure
Characteristic
Example use
Linked list
Nodes linked by pointers; fast insertion/deletion
Ordered data with frequent insert/remove
Stack
Last-in, first-out (LIFO)
Function calls, Undo history
Queue
First-in, first-out (FIFO)
Print queue, task scheduling
All of these are implemented with a combination of structs, pointers, and malloc. This lesson brings together everything we have learned so far!
Linked List β A Chain Connected by Pointers
A linked list is a sequence in which each element (node) contains data and a pointer to the next node.
Node definition
typedefstructNode {
int data; // the stored datastructNode *next; // pointer to the next node
} Node;
Picture of memory
10
nextβ
β
20
nextβ
β
30
nextβ
β
NULL
Key operations
// (1) Create a nodeNode* createNode(int val) {
Node *n = malloc(sizeof(Node));
n->data = val;
n->next = NULL;
return n;
}
// (2) Insert at the front (O(1) β fast!)voidpushFront(Node **head, int val) {
Node *n = createNode(val);
n->next = *head; // new node's next = old head
*head = n; // head now points to new node
}
// (3) Print all elementsvoidprintList(Node *head) {
for (Node *p = head; p != NULL; p = p->next)
printf("%d β ", p->data);
printf("NULL\n");
}
// (4) Free the memory (forgetting leaks!)voidfreeList(Node *head) {
while (head) {
Node *tmp = head->next;
free(head);
head = tmp;
}
}
Front insertion
O(1) β very fast
Search
O(n) β traverse from the head
Compared to arrays
No index access; random access is not its strength
Stack β Last In, First Out (LIFO)
A stack pops off the most recently pushed item first. Imagine stacking plates. Function calls are also managed on a stack.
Stack visualization
10
20
30
β TOP (items come off here)
// push: add to the topvoidpush(Node **top, int val) {
Node *n = createNode(val);
n->next = *top;
*top = n;
}
// pop: remove from the topintpop(Node **top) {
if (*top == NULL) return -1;
Node *tmp = *top;
int val = tmp->data;
*top = tmp->next;
free(tmp);
return val;
}
Everyday examples: the Back button in a browser, Ctrl+Z (Undo), and the call stack that tracks function calls β all of these use a stack.
Queue β First In, First Out (FIFO)
A queue removes items in the same order they were added β just like a checkout line.
Queue visualization
Out β
10
20
30
β In
// enqueue: add to the tailvoidenqueue(Node **head, Node **tail, int val) {
Node *n = createNode(val);
if (*tail) (*tail)->next = n;
else *head = n;
*tail = n;
}
// dequeue: remove from the headintdequeue(Node **head, Node **tail) {
if (!*head) return -1;
Node *tmp = *head;
int val = tmp->data;
*head = tmp->next;
if (!*head) *tail = NULL;
free(tmp);
return val;
}
Everyday examples: printer queues, OS task schedulers, chat message ordering.
Array vs Linked List vs Stack vs Queue
Operation
Array
Linked list
Stack
Queue
Insert at front
O(n)
O(1)
β
β
Append at back
O(1)
O(1)*
O(1)
O(1)
Random access
O(1)
O(n)
β
β
Insert in middle
O(n)
O(1)β
β
β
* with a tail pointer. β when the insertion point is known.
Linked List Demo
Add and remove elements from a linked list with the buttons, and watch the structure update in real time.